1 /*
2  * XPilot NG, a multiplayer space war game.
3  *
4  * Copyright (C) 2005 Kristian S�derblom <kps@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include "xpcommon.h"
22 
23 #define ARRAYLIST_INITIAL_NUM_ELEMENTS 16
24 #define ARRAYLIST_ELEMENT_ALIGNMENT sizeof(double)
25 
Arraylist_clear(arraylist_t * alp)26 void Arraylist_clear(arraylist_t *alp)
27 {
28     alp->num_elements = 0;
29 }
30 
Arraylist_get(arraylist_t * alp,int ind)31 void *Arraylist_get(arraylist_t *alp, int ind)
32 {
33     if (ind < 0 || ind >= alp->num_elements)
34 	return NULL;
35     return Arraylist_get_element_pointer(alp, ind);
36 }
37 
Arraylist_add(arraylist_t * alp,void * element)38 int Arraylist_add(arraylist_t *alp, void *element)
39 {
40     size_t n;
41     void *p;
42 
43     if (alp->num_elements < alp->max_elements) {
44 	p = Arraylist_get_element_pointer(alp, alp->num_elements);
45 	memcpy(p, element, alp->element_size);
46 	return alp->num_elements++;
47     }
48 
49     if (alp->max_elements >= ARRAYLIST_INITIAL_NUM_ELEMENTS)
50 	n = alp->max_elements * 2;
51     else
52 	n = ARRAYLIST_INITIAL_NUM_ELEMENTS;
53     p = realloc(alp->elements, n * alp->element_padded_size);
54     if (p == NULL)
55 	return -1;
56 
57     alp->elements = p;
58     alp->max_elements = n;
59 
60     return Arraylist_add(alp, element);
61 }
62 
Arraylist_fast_remove(arraylist_t * alp,int ind)63 void Arraylist_fast_remove(arraylist_t *alp, int ind)
64 {
65     void *p, *last_p;
66 
67     /* get pointer to the element to remove */
68     p = Arraylist_get(alp, ind);
69     if (!p)
70 	/* warn or return error ? */
71 	return;
72 
73     /* last element? */
74     if (ind == alp->num_elements - 1) {
75 	/* no need to copy anything */
76 	alp->num_elements--;
77 	return;
78     }
79 
80     /* copy last element to index 'ind' */
81     last_p = Arraylist_get(alp, alp->num_elements - 1);
82     assert(last_p != NULL);
83     memcpy(p, last_p, alp->element_padded_size);
84     alp->num_elements--;
85 }
86 
Arraylist_alloc(size_t element_size)87 arraylist_t *Arraylist_alloc(size_t element_size)
88 {
89     arraylist_t *alp = XCALLOC(arraylist_t, 1);
90     size_t padded_size = element_size;
91 
92     if (((element_size % ARRAYLIST_ELEMENT_ALIGNMENT) != 0)
93 	&& element_size != 1
94 	&& element_size != 2
95 	&& element_size != 4) {
96 	padded_size /= ARRAYLIST_ELEMENT_ALIGNMENT;
97 	padded_size *= ARRAYLIST_ELEMENT_ALIGNMENT;
98 	padded_size += ARRAYLIST_ELEMENT_ALIGNMENT;
99 
100 	/*warn("Arraylist_create: Increasing element size from %d to %d.",
101 	  element_size, padded_size);*/
102     }
103 
104     if (alp == NULL)
105 	goto failed;
106 
107     alp->elements = calloc(ARRAYLIST_INITIAL_NUM_ELEMENTS, padded_size);
108     if (alp->elements == NULL)
109 	goto failed;
110 
111     alp->element_size = element_size;
112     alp->element_padded_size = padded_size;
113     alp->num_elements = 0;
114     alp->max_elements = ARRAYLIST_INITIAL_NUM_ELEMENTS;
115 
116     return alp;
117 
118  failed:
119     return NULL;
120 }
121 
Arraylist_free(arraylist_t * alp)122 void Arraylist_free(arraylist_t *alp)
123 {
124     assert(alp != NULL);
125     assert(alp->elements != NULL);
126     XFREE(alp->elements);
127     XFREE(alp);
128 }
129