Annotation of libelwix/src/array.c, revision 1.9
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.9 ! misho 6: * $Id: array.c,v 1.8.4.2 2019/01/23 17:40:37 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.6 misho 15: Copyright 2004 - 2019
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * array_Init() - Create and initialize dynamic array
51: *
52: * @numItems = Number of Items
53: * return: NULL error, != NULL allocated memory for array
54: */
1.2 misho 55: array_t *
1.1 misho 56: array_Init(int numItems)
57: {
58: array_t *arr = NULL;
59:
60: arr = e_malloc(sizeof(array_t));
61: if (!arr)
62: return NULL;
63:
64: arr->arr_last = -1;
65: arr->arr_num = numItems;
66: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
67: if (!arr->arr_data) {
68: e_free(arr);
69: return NULL;
70: } else
1.9 ! misho 71: memset(arr->arr_data, 0, array_Size(arr) * sizeof(intptr_t));
1.1 misho 72:
73: return arr;
74: }
1.8 misho 75:
76: /*
77: * array_Init2() - Initialize dynamic array
78: *
79: * @arr = Allocated array variable
80: * @numItems = Number of Items
81: * return: NULL error, != NULL allocated memory for array
82: */
83: array_t *
84: array_Init2(array_t * __restrict arr, int numItems)
85: {
86: if (!arr)
87: return array_Init(numItems);
88:
89: if (array_Size(arr))
90: return NULL; /* already allocated array! */
91:
92: arr->arr_last = -1;
93: arr->arr_num = numItems;
94: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
95: if (!arr->arr_data) {
96: e_free(arr);
97: return NULL;
98: } else
1.9 ! misho 99: memset(arr->arr_data, 0, array_Size(arr) * sizeof(intptr_t));
1.8 misho 100:
101: return arr;
102: }
103:
1.1 misho 104:
105: /*
106: * array_From() - Create and fill array from array with pointers
107: *
108: * @pargv = Array with pointers
109: * @argc = Number of Items, if 0 walk through argv and stop when reach NULL item
110: * return: NULL error, != NULL allocated new array
111: */
112: array_t *
113: array_From(const char *** __restrict pargv, int argc)
114: {
115: array_t *arr = NULL;
116: const char **a = NULL;
117: register int num = 0;
118:
119: if (!pargv || !*pargv || argc < 0)
120: return NULL;
121:
122: if (argc)
123: num = argc;
124: else
125: for (a = *pargv; *a; a++, num++);
126:
127: arr = array_Init(num);
128: if (!arr)
129: return NULL;
130: else {
131: memcpy(arr->arr_data, *pargv, array_Size(arr) * sizeof(intptr_t));
132: arr->arr_last = array_Size(arr) - 1;
133: }
134:
135: return arr;
136: }
137:
138: /*
139: * array_To() - Create and fill array with pointers from dynamic array
140: *
141: * @arr = Array
142: * return: NULL error, != NULL allocated memory for array, NULL terminated
143: */
144: char **
145: array_To(array_t * __restrict arr)
146: {
147: char **args = NULL;
148:
149: if (!arr || !array_Size(arr))
150: return NULL;
151:
152: args = (char **) e_calloc(array_Size(arr) + 1, sizeof(char*));
153: if (!args)
154: return NULL;
155: else
156: memcpy(args, arr->arr_data, array_Size(arr) * sizeof(char*));
157: args[array_Size(arr)] = NULL;
158:
159: return args;
160: }
161:
162: /*
163: * array_Free() - Free all data in dynamic array items
164: * (WARNING! If assign static array dont use this!!!)
165: *
166: * @arr = Array
167: * return: none
168: */
1.2 misho 169: void
1.1 misho 170: array_Free(array_t * __restrict arr)
171: {
172: register int i;
173:
174: if (!arr)
175: return;
176:
177: for (i = 0; i < array_Size(arr); i++)
1.9 ! misho 178: if (arr->arr_data[i])
1.1 misho 179: e_free(arr->arr_data[i]);
180:
1.9 ! misho 181: array_Zero(arr);
1.1 misho 182: }
183:
184: /*
185: * array_Destroy() - Free and destroy dynamic array
186: *
187: * @parr = Array
188: * return: none
189: */
1.2 misho 190: void
1.1 misho 191: array_Destroy(array_t ** __restrict parr)
192: {
193: if (!parr || !*parr)
194: return;
195:
196: if ((*parr)->arr_data)
197: e_free((*parr)->arr_data);
198: e_free(*parr);
199: *parr = NULL;
1.6 misho 200: }
201:
202: /*
1.9 ! misho 203: * array_Destroy2() - Free data in dynamic array
! 204: *
! 205: * @parr = Array
! 206: * return: none
! 207: */
! 208: void
! 209: array_Destroy2(array_t * __restrict arr)
! 210: {
! 211: if (!arr)
! 212: return;
! 213:
! 214: if (arr->arr_data)
! 215: e_free(arr->arr_data);
! 216: memset(arr, 0, sizeof(array_t));
! 217: }
! 218: /*
1.6 misho 219: * array_Reset() - Reset array to initial state
220: *
221: * @parr = Array
1.9 ! misho 222: * @purge = Purge all data, if <>0 then will be free entire data memory
1.6 misho 223: * return: none
224: */
225: void
226: array_Reset(array_t * __restrict arr, int purge)
227: {
228: if (!arr)
229: return;
230:
231: if (purge && arr->arr_data) {
232: e_free(arr->arr_data);
1.7 misho 233: arr->arr_num = 0;
1.6 misho 234: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
235: }
236:
237: array_Zero(arr);
1.1 misho 238: }
239:
240: /*
241: * array_Len() - Get last used element in dynamic array (array Length)
242: *
243: * @arr = Array
244: * return: -1 empty or >-1 position of last used element
245: */
1.2 misho 246: int
1.1 misho 247: array_Len(array_t * __restrict arr)
248: {
249: register int i;
250:
251: if (!arr)
252: return -1;
253:
254: for (i = array_Size(arr); i && !arr->arr_data[i - 1]; i--);
255:
256: return --i;
257: }
258:
259: /*
260: * array_Grow() - Grow/Shrink dynamic array, Use with care when it shrink!!!
261: *
262: * @arr = Array
263: * @newNumItems = Number of Items
264: * @freeShrink = Free elements before shrink array
265: * return: -1 error, 0 ok
266: */
267: int
268: array_Grow(array_t * __restrict arr, int newNumItems, int freeShrink)
269: {
270: void **data;
271: int n = 0;
272: register int i;
273:
274: if (!arr)
275: return -1;
276:
277: if (arr->arr_num == newNumItems)
278: return 0;
279: if (array_Size(arr) < newNumItems) {
280: n = newNumItems - array_Size(arr);
281: } else if (freeShrink)
282: for (i = newNumItems; i < arr->arr_num; i++)
283: if (arr->arr_data[i])
284: e_free(arr->arr_data[i]);
285:
286: arr->arr_num = newNumItems;
287: if (array_Size(arr)) {
288: data = e_realloc(arr->arr_data, array_Size(arr) * sizeof(intptr_t));
289: if (!data)
290: return -1;
291: else
292: arr->arr_data = data;
293:
294: memset(arr->arr_data + (array_Size(arr) - n), 0, n * sizeof(intptr_t));
295: arr->arr_last = array_Len(arr);
296: } else {
297: if (arr->arr_data)
298: e_free(arr->arr_data);
299: arr->arr_data = NULL;
300: arr->arr_last = -1;
301: }
302:
303: return 0;
304: }
305:
306: /*
307: * array_Vacuum() - Vacuum dynamic array, empty elements will be deleted
308: *
309: * @arr = Array
310: * @fromWhere = 1 begin, 2 ALL empty elements
311: * return: -1 error, 0 ok
312: */
313: int
314: array_Vacuum(array_t * __restrict arr, int fromWhere)
315: {
316: register int i, j, num;
317: int cx = 0;
318:
319: if (!arr)
320: return -1;
321: else
322: fromWhere &= 0x7;
323:
324: num = array_Size(arr);
325: #ifdef VACUUM_RIGHT
326: if (fromWhere & VACUUM_RIGHT) {
327: for (cx = 0, i = num - 1; i && !arr->arr_data[i]; i--, cx++);
328: num -= cx;
329: }
330: #endif
331: if (fromWhere & VACUUM_LEFT) {
332: for (i = 0; i < num && !arr->arr_data[i]; i++);
333: if (i) {
334: memmove(arr->arr_data, arr->arr_data + i, (num - i) * sizeof(intptr_t));
335: memset(arr->arr_data + (num - i), 0, i * sizeof(intptr_t));
336:
337: num -= i;
338: cx += i;
339: }
340: }
341: if (fromWhere & VACUUM_BETWEEN) {
342: for (i = 0; i < num; i++) {
343: if (arr->arr_data[i])
344: continue;
345:
346: for (j = i; j < num && !arr->arr_data[j]; j++);
347:
348: memmove(arr->arr_data + i, arr->arr_data + j, (num - j) * sizeof(intptr_t));
349: memset(arr->arr_data + i + (num - j), 0, (j - i) * sizeof(intptr_t));
350:
351: num -= j - i;
352: cx += j - i;
353: }
354: }
355:
356: arr->arr_last = array_Len(arr);
357: return cx;
358: }
359:
360: /*
361: * array_Concat() Concat source array to destination array
362: *
363: * @dest = Destination array
364: * @src = Source array
365: * return: -1 error; >0 new count of destination array
366: */
367: int
368: array_Concat(array_t * __restrict dest, array_t * __restrict src)
369: {
370: int n;
371:
372: if (!dest || !src)
373: return -1;
374:
375: n = array_Size(dest);
376: if (array_Grow(dest, n + array_Size(src), 0))
377: return -1;
378: memcpy(dest->arr_data + n, src->arr_data, array_Size(src) * sizeof(intptr_t));
379:
380: dest->arr_last = array_Len(dest);
381: return array_Size(dest);
382: }
383:
384: /*
385: * array_Copy() Copy source array to destination array
386: *
1.3 misho 387: * @dest = Destination array, after use free with array_Destroy()
1.1 misho 388: * @src = Source array
389: * return: -1 error; >0 count of destination array
390: */
391: int
392: array_Copy(array_t ** __restrict dest, array_t * __restrict src)
393: {
394: if (!dest || !src)
395: return -1;
396:
397: *dest = array_Init(array_Size(src));
398: if (!*dest)
399: return -1;
400: else
401: (*dest)->arr_last = src->arr_last;
402:
403: memcpy((*dest)->arr_data, src->arr_data, array_Size(*dest) * sizeof(intptr_t));
404: return array_Size(*dest);
405: }
406:
407: /*
408: * array_Elem() - Always GET/PUT element into dynamic array, if not enough elements grow array
409: *
410: * @arr = Array
411: * @n = Position
412: * @data = Element, if set NULL GET element at position or !=NULL PUT element at position
413: * return: -1 error or !=-1 return element at position
414: */
1.2 misho 415: void *
1.1 misho 416: array_Elem(array_t * __restrict arr, int n, void *data)
417: {
418: void *dat = NULL;
419:
420: if (!arr)
421: return (void*) -1;
422:
423: if (n >= array_Size(arr) && array_Grow(arr, n + 1, 0))
424: return (void*) -1;
425:
426: dat = array_Get(arr, n);
427: if (data)
428: array_Set(arr, n, data);
429:
430: return dat;
431: }
432:
433: /*
434: * array_Push() - Push element into dynamic array like stack manner, place at first empty position
435: *
436: * @arr = Array
437: * @data = Element, if set NULL return only first empty position
438: * @nogrow = Don't grow array if not enough space
439: * return: -1 not found empty position, array is full!, >-1 return position of stored element into array
440: */
1.2 misho 441: int
442: array_Push(array_t * __restrict arr, void *data, int nogrow)
1.1 misho 443: {
444: int ret = -1;
445:
446: if (!arr)
447: return -1;
448: else
449: ret = array_Last(arr) + 1;
450: if (nogrow && ret >= array_Size(arr))
451: return -1;
452: if (!nogrow && ret >= array_Size(arr) && array_Grow(arr, ret + 1, 0))
453: return -1;
454:
1.2 misho 455: ret = ++arr->arr_last;
456: arr->arr_data[arr->arr_last] = data;
1.1 misho 457:
458: return ret;
459: }
460:
461: /*
462: * array_Pop() - Pop element from dynamic array like stack manner, last used position
463: *
464: * @arr = Array
465: * @data = Element, if set NULL return only last used position
466: * @nodel = Don't delete after Pop element
467: * return: -1 not found used position, array is empty!, >-1 return element position
468: */
1.2 misho 469: int
1.1 misho 470: array_Pop(array_t * __restrict arr, void ** __restrict data, int nodel)
471: {
472: int ret = -1;
473:
474: if (!arr)
475: return -1;
476:
1.2 misho 477: if ((ret = array_Last(arr)) != -1) {
478: if (data)
479: *data = arr->arr_data[arr->arr_last];
480: if (!nodel)
481: arr->arr_data[arr->arr_last] = NULL;
482: arr->arr_last--;
483: }
1.1 misho 484:
485: return ret;
486: }
487:
488: /*
489: * array_Args() Parse and make array from arguments ... (input string will be modified!!!
1.3 misho 490: * and output array must be free with array_Destroy() after use!)
1.1 misho 491: *
492: * @psArgs = Input arguments line, after execute string is modified!!!
493: * @nargs = Maximum requested count of arguments from input string psArgs, if 0 all psArgs
494: * @csDelim = Delimiter(s) for separate
495: * @parr = Output array of arguments ... (must be free with array_Destroy() after use!)
496: * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
497: */
498: int
499: array_Args(char * __restrict psArgs, int nargs, const char *csDelim, array_t ** __restrict parr)
500: {
501: char **app;
502: register int i;
503:
504: if (!psArgs || !csDelim || !parr)
505: return -1;
506:
507: if (nargs)
508: i = nargs;
509: else
510: i = str_ArgsNum(psArgs, csDelim);
511:
512: *parr = array_Init(i);
513: if (!*parr)
514: return -1;
515:
516: for (i = 0, app = (char**) (*parr)->arr_data;
517: app < (char**) (*parr)->arr_data + (*parr)->arr_num &&
518: (*app = strsep((char **) &psArgs, csDelim));
519: **app ? i++ : i, **app ? app++ : app);
520:
521: (*parr)->arr_last = i - 1;
522: return i;
523: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>