ebuf.c : fix of a nasty bug which rendered the function Neuro_MultiAllocEBuf complete...
[neuro.git] / src / memory / ebuf.c
blob8122fa4fa5eeb8ec8bc77ed084ca55bf2d1c3476
2 /*
3 * libneuro, a light weight abstraction of high or lower libraries
4 * and toolkit for applications.
5 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 /* ebuf.c
24 * interface to the EBUF header.
25 * EBUF is used in a same manner as we use linked lists;
26 * It is an easy way to have a growing structure array.
27 * The EBUF header elements are hidden to external programs.
30 /*-------------------- Extern Headers Including --------------------*/
31 #include <stdlib.h>
33 /*-------------------- Local Headers Including ---------------------*/
34 #include <global.h>
36 /*-------------------- Main Module Header --------------------------*/
37 #include <ebuf.h>
39 /*-------------------- Other ----------------------------*/
41 NEURO_MODULE_CHANNEL("ebuf");
43 /* take note that the typedef is in the ebuf.h header!!
45 * this is the core EBUF header. It is
46 * 16 bytes in size and handles structures
47 * so their use is memory leak less, safe and
48 * easy. There is only one of this header
49 * structure per EBUF iteration. The actual
50 * data we hold is in the **buffer variable!
52 struct EBUF
54 /* this pointer will point to the structures
55 * the external programs give us. This is where the
56 * data is kept and grows.
58 void **buffer;
60 /* how many overhead memory inside the **buffer we have
61 * allocated in advance.
63 u32 mem;
65 /* the current total number of elements inside **buffer */
66 u32 total;
68 /* callback that is not necessarily needed. This callback
69 * is used if the input structure itself has allocated elements
70 * that needs to be freed for every iteration.
72 void (*callback)(void *src);
75 /* doesn't seem to be ISO C ANSI compliant.
76 * I'm leaving the code here for future
77 * reference.
80 #define GIVEEBUF(__eng, __elem) \
81 ({ \
82 register void ***__buf; \
83 void *__result; \
84 if (__elem > __eng->total) \
85 __result = NULL; \
86 __buf = (void***)&__eng->buffer; \
87 if ((*__buf)[__elem]) \
88 __result = (*__buf)[__elem]; \
89 else \
90 __result = NULL; \
91 __result; })
94 /*-------------------- Global Variables ----------------------------*/
96 /*-------------------- Static Variables ----------------------------*/
98 /*-------------------- Static Prototypes ---------------------------*/
100 /*-------------------- Static Functions ----------------------------*/
102 /*-------------------- Global Functions ----------------------------*/
104 void
105 Neuro_CreateEBuf(EBUF **eng)
108 /* we allocate only the header EBUF structure */
109 *eng = (EBUF*)calloc(1, sizeof(EBUF));
111 /* set ALL the elements in the header EBUF structure
112 * to their default NULL or 0 values.
114 (*eng)->mem = 0;
115 (*eng)->total = 0;
116 (*eng)->buffer = NULL;
117 (*eng)->callback = NULL;
121 void
122 Neuro_SetcallbEBuf(EBUF *eng, void (*callback)(void *src))
124 eng->callback = callback;
127 /* sptp stands for : size of the pointer type of the structure
128 * the external program will pass to EBUF. example :
129 * sizeof(struct foo *) or sizeof(foo *)
131 * sobj stands for : size of the actual structure the external
132 * program will pass to EBUF. example : sizeof(struct foo)
133 * or sizeof(foo)
135 void
136 Neuro_AllocEBuf(EBUF *eng, size_t sptp, size_t sobj)
138 void ***buf;
139 u32 *total;
140 u32 *mem;
142 if (!eng)
143 return;
145 buf = &eng->buffer;
146 total = &eng->total;
147 mem = &eng->mem;
150 Debug_Val(0, "debug : %d\n", sptp);
151 Debug_Val(0, "before mem %d\n", mem);
154 if (!buf)
156 NEURO_ERROR("Tried to allocate in a NULL buffer", NULL);
157 return;
160 /* we will allocate or reallocate the **
161 * which is what points to the * elements
163 if (*buf == NULL)
165 /* we allocate extra amount of elements to speed up
166 * allocation time. MEMORY_ALLOC_OVERH is set in the
167 * ebuf.h header.
169 *buf = calloc(MEMORY_ALLOC_OVERH, sptp);
170 *total = 0;
172 /* we set the mem EBUF element to how many overhead
173 * times we could add data without the need to reallocate.
175 *mem = MEMORY_ALLOC_OVERH - 1;
177 else if ((*mem * sptp) < sptp)
179 if (*buf == NULL)
181 /* theres a big problem */
182 NEURO_ERROR("Memory buffer unknown error", NULL);
183 return;
186 /* we again allocate more memory than needed */
187 *buf = realloc(*buf, sptp * (*total + MEMORY_ALLOC_OVERH));
189 /* keep track of how many times we don't need to reallocate */
190 *mem = MEMORY_ALLOC_OVERH - 1;
192 else
194 /* We now will use an emplacement that was allocated in advance.
195 * Since we will use an element, we decrement the overhead EBUF
196 * mem variable value.
198 *mem -= 1;
201 /* Debug_Val(0, "EBUF -- after mem %d\n", *mem); */
203 /* in addition to allocating the **buffer pointer, we also
204 * need to allocate the actual structure it will point to.
206 * in technical terms, we now allocate the * .
208 (*buf)[*total] = calloc(1, sobj);
211 *total = *total + 1;
214 void
215 Neuro_MultiAllocEBuf(EBUF *eng, u32 amount, size_t sptp, size_t sobj)
217 void ***buf;
218 u32 *total;
219 u32 *mem;
220 int i = 0;
222 buf = &eng->buffer;
223 total = &eng->total;
224 mem = &eng->mem;
227 if (amount == 1)
229 Neuro_AllocEBuf(eng, sptp, sobj);
230 return;
233 i = amount;
235 while (i-- > 0)
237 Neuro_AllocEBuf(eng, sptp, sobj);
240 #if temp
241 /* we only do anything if the buffer doesn't contain anything
242 * to avoid memory leaks.
244 if (*buf == NULL)
246 *buf = calloc(amount, sptp);
247 *total = amount - 1;
248 *mem = 0;
251 i = *total + 1;
253 /* we need to allocate every * elements in the ** */
254 while (i-- > 0)
256 (*buf)[i] = calloc(1, sobj);
259 #endif /* temp */
262 void
263 Neuro_SCleanEBuf(EBUF *eng, void *object)
265 void *buf;
266 u32 elem;
267 u32 total;
269 if (!eng || !object)
271 NEURO_WARN("Element eng or object is NULL", NULL);
272 return;
275 total = Neuro_GiveEBufCount(eng);
277 /* normally, EBUF functions input integers which are
278 * corresponding to the ** array. But in this function
279 * we input the actual pointer to the element.
281 * This puts the actual integer corresponding to the
282 * pointer object from the ** array and puts it in elem.
284 if (Neuro_GiveEBufElem(eng, object, &elem))
286 NEURO_WARN("Element wasn't found in the buffer", NULL);
287 return;
290 /* we call the callback that will clean
291 * allocated pointers in the structure if
292 * theres one.
294 if (eng->callback != NULL)
295 eng->callback(object);
296 else
297 NEURO_TRACE("There's no cleaning callback for this buffer (this could be normal)", NULL);
299 free(object);
302 /* now that the object is freed, we will attempt to fill its
303 * emplacement with the last one.
306 /* check to see if the one we want to remove is the last one */
307 if (total != elem)
309 /* get the last one */
310 buf = Neuro_GiveEBuf(eng, total);
312 /* make the one we just deleted point to the last one */
313 Neuro_SetEBuf(eng, Neuro_GiveEBufAddr(eng, elem), buf);
316 /* make the last element point to NULL so it can be reused*/
317 Neuro_SetEBuf(eng, Neuro_GiveEBufAddr(eng, total), NULL);
319 eng->mem++; /* add an extra mem because we now have an extra slot free */
321 eng->total--;
324 void
325 Neuro_CleanEBuf(EBUF **engi)
327 void *buf;
328 EBUF *eng;
329 u32 i;
332 * this is to avoid very big and puzzling call to the **engi element like
333 * (*engi)->mem or engi[0]->mem. This is for cleaner code.
335 eng = *engi;
337 if (!eng)
338 return;
340 buf = &eng->buffer;
341 i = eng->total;
343 /* loop all the elements in the EBUF **, call the
344 * callback(if theres one!) with the actual element
345 * as the argument and finally free the element.
347 * in short : free every * in the ** array.
349 while (i-- > 0)
352 buf = Neuro_GiveEBuf(eng, i);
354 if (buf)
356 if (eng->callback)
358 eng->callback(buf);
360 free(buf);
362 /* Debug_Val(0, "#%d -- cleaned\n", i); */
365 /* free the actual ** array */
366 if (eng->buffer != NULL)
368 free(eng->buffer);
369 eng->buffer = NULL;
372 /* Debug_Val(0, "cleaned %d elements\n", eng->total); */
373 eng->total = 0;
374 eng->mem = 0;
376 /* free the actual EBUF structure */
377 if (*engi != NULL)
379 free(*engi);
380 *engi = NULL;
384 u32
385 Neuro_GiveEBufCount(EBUF *eng)
387 if (!eng)
388 return 0;
390 return (eng->total > 0 ? eng->total -1 : 0);
393 void *
394 Neuro_GiveEBuf(EBUF *eng, u32 elem)
396 if (!eng)
397 return NULL;
399 if (Neuro_EBufIsEmpty(eng))
400 return NULL;
402 if (elem > eng->total)
403 return NULL;
406 if (eng->buffer[elem])
407 return eng->buffer[elem];
408 else
409 return NULL;
412 void *
413 Neuro_GiveCurEBuf(EBUF *eng)
415 if (!eng)
416 return NULL;
418 if (Neuro_EBufIsEmpty(eng))
419 return NULL;
422 if (eng->buffer[eng->total - 1])
423 return (eng->buffer[eng->total - 1]);
424 else
425 return NULL;
428 void **
429 Neuro_GiveEBufCore(EBUF *eng)
431 if (!eng)
432 return NULL;
434 return eng->buffer;
437 /* returns 1 on error and 0 if all is ok
439 * for a certain pointer, we return its corresponding array
440 * number.
443 Neuro_GiveEBufElem(EBUF *eng, void *object, u32 *elem)
445 void *buf;
446 u32 i;
448 if (!eng || !object)
450 *elem = 0;
451 return 1;
454 buf = &eng->buffer;
455 i = eng->total;
457 while (i-- > 0)
459 buf = Neuro_GiveEBuf(eng, i);
460 if (buf == object)
462 *elem = i;
463 return 0;
468 return 1;
471 /* give the address of an EBUF * element */
472 void **
473 Neuro_GiveEBufAddr(EBUF *eng, u32 elem)
475 void ***buf;
477 if (!eng)
478 return NULL;
481 buf = (void***)&eng->buffer;
483 if ((*buf)[elem])
484 return &(*buf)[elem];
485 else
486 return NULL;
489 /* to move EBUF elements from a position to another
490 * watch out for memory leaks!
492 void
493 Neuro_SetEBuf(EBUF *eng, void **to, void *from)
495 if (!eng || !to || !from)
496 return;
498 *to = from;
500 return;
503 /* copy an EBUF header to another */
504 void
505 Neuro_CopyEBuf(EBUF *to, EBUF *from)
507 if (!to || !from)
508 return;
510 to->buffer = from->buffer;
511 to->mem = from->mem;
512 to->total = from->total;
515 /* reset the EBUF element
517 * NOTE : should only be called if the EBUF address
518 * was passed to another EBUF or it was copied to another
519 * using the Neuro_CopyEBuf function!!!
520 * Else, there will be a big memory leak.
522 void
523 Neuro_ResetEBuf(EBUF *eng)
525 if (!eng)
526 return;
528 eng->buffer = NULL;
529 eng->total = 0;
530 eng->mem = 0;
533 /* returns 1 if the EBUF is empty, 0 if its NOT empty and
534 * 2 if the EBUF passed does not exist. */
536 Neuro_EBufIsEmpty(EBUF *eng)
538 if (!eng)
539 return 2;
541 return (eng->total == 0 ? 1 : 0);