Line data Source code
1 : /*
2 : * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
3 : *
4 : * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5 : * Michael Clark <michael@metaparadigm.com>
6 : *
7 : * This library is free software; you can redistribute it and/or modify
8 : * it under the terms of the MIT license. See COPYING for details.
9 : *
10 : */
11 :
12 : #include "config.h"
13 :
14 : #include <limits.h>
15 :
16 : #ifdef STDC_HEADERS
17 : #include <stdlib.h>
18 : #include <string.h>
19 : #endif /* STDC_HEADERS */
20 :
21 : #if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
22 : #include <strings.h>
23 : #endif /* HAVE_STRINGS_H */
24 :
25 : #ifndef SIZE_T_MAX
26 : #if SIZEOF_SIZE_T == SIZEOF_INT
27 : #define SIZE_T_MAX UINT_MAX
28 : #elif SIZEOF_SIZE_T == SIZEOF_LONG
29 : #define SIZE_T_MAX ULONG_MAX
30 : #elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
31 : #define SIZE_T_MAX ULLONG_MAX
32 : #else
33 : #error Unable to determine size of size_t
34 : #endif
35 : #endif
36 :
37 : #include "arraylist.h"
38 :
39 0 : struct array_list *array_list_new(array_list_free_fn *free_fn)
40 : {
41 0 : return array_list_new2(free_fn, ARRAY_LIST_DEFAULT_SIZE);
42 : }
43 :
44 453112 : struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size)
45 : {
46 : struct array_list *arr;
47 :
48 453112 : arr = (struct array_list *)malloc(sizeof(struct array_list));
49 453112 : if (!arr)
50 0 : return NULL;
51 453112 : arr->size = initial_size;
52 453112 : arr->length = 0;
53 453112 : arr->free_fn = free_fn;
54 453112 : if (!(arr->array = (void **)malloc(arr->size * sizeof(void *))))
55 : {
56 0 : free(arr);
57 0 : return NULL;
58 : }
59 453112 : return arr;
60 : }
61 :
62 453112 : extern void array_list_free(struct array_list *arr)
63 : {
64 : size_t i;
65 1993160 : for (i = 0; i < arr->length; i++)
66 1540050 : if (arr->array[i])
67 1537590 : arr->free_fn(arr->array[i]);
68 453112 : free(arr->array);
69 453112 : free(arr);
70 453112 : }
71 :
72 1329950 : void *array_list_get_idx(struct array_list *arr, size_t i)
73 : {
74 1329950 : if (i >= arr->length)
75 0 : return NULL;
76 1329950 : return arr->array[i];
77 : }
78 :
79 1540050 : static int array_list_expand_internal(struct array_list *arr, size_t max)
80 : {
81 : void *t;
82 : size_t new_size;
83 :
84 1540050 : if (max < arr->size)
85 1531360 : return 0;
86 : /* Avoid undefined behavior on size_t overflow */
87 8684 : if (arr->size >= SIZE_T_MAX / 2)
88 0 : new_size = max;
89 : else
90 : {
91 8684 : new_size = arr->size << 1;
92 8684 : if (new_size < max)
93 0 : new_size = max;
94 : }
95 8684 : if (new_size > (~((size_t)0)) / sizeof(void *))
96 0 : return -1;
97 8684 : if (!(t = realloc(arr->array, new_size * sizeof(void *))))
98 0 : return -1;
99 8684 : arr->array = (void **)t;
100 8684 : arr->size = new_size;
101 8684 : return 0;
102 : }
103 :
104 187968 : int array_list_shrink(struct array_list *arr, size_t empty_slots)
105 : {
106 : void *t;
107 : size_t new_size;
108 :
109 187968 : new_size = arr->length + empty_slots;
110 187968 : if (new_size == arr->size)
111 0 : return 0;
112 187968 : if (new_size > arr->size)
113 0 : return array_list_expand_internal(arr, new_size);
114 187968 : if (new_size == 0)
115 601 : new_size = 1;
116 :
117 187968 : if (!(t = realloc(arr->array, new_size * sizeof(void *))))
118 0 : return -1;
119 187968 : arr->array = (void **)t;
120 187968 : arr->size = new_size;
121 187968 : return 0;
122 : }
123 :
124 : //static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data)
125 0 : int array_list_put_idx(struct array_list *arr, size_t idx, void *data)
126 : {
127 0 : if (idx > SIZE_T_MAX - 1)
128 0 : return -1;
129 0 : if (array_list_expand_internal(arr, idx + 1))
130 0 : return -1;
131 0 : if (idx < arr->length && arr->array[idx])
132 0 : arr->free_fn(arr->array[idx]);
133 0 : arr->array[idx] = data;
134 0 : if (idx > arr->length)
135 : {
136 : /* Zero out the arraylist slots in between the old length
137 : and the newly added entry so we know those entries are
138 : empty.
139 : e.g. when setting array[7] in an array that used to be
140 : only 5 elements longs, array[5] and array[6] need to be
141 : set to 0.
142 : */
143 0 : memset(arr->array + arr->length, 0, (idx - arr->length) * sizeof(void *));
144 : }
145 0 : if (arr->length <= idx)
146 0 : arr->length = idx + 1;
147 0 : return 0;
148 : }
149 :
150 1540050 : int array_list_add(struct array_list *arr, void *data)
151 : {
152 : /* Repeat some of array_list_put_idx() so we can skip several
153 : checks that we know are unnecessary when appending at the end
154 : */
155 1540050 : size_t idx = arr->length;
156 1540050 : if (idx > SIZE_T_MAX - 1)
157 0 : return -1;
158 1540050 : if (array_list_expand_internal(arr, idx + 1))
159 0 : return -1;
160 1540050 : arr->array[idx] = data;
161 1540050 : arr->length++;
162 1540050 : return 0;
163 : }
164 :
165 0 : void array_list_sort(struct array_list *arr, int (*compar)(const void *, const void *))
166 : {
167 0 : qsort(arr->array, arr->length, sizeof(arr->array[0]), compar);
168 0 : }
169 :
170 0 : void *array_list_bsearch(const void **key, struct array_list *arr,
171 : int (*compar)(const void *, const void *))
172 : {
173 0 : return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]), compar);
174 : }
175 :
176 824610 : size_t array_list_length(struct array_list *arr)
177 : {
178 824610 : return arr->length;
179 : }
180 :
181 0 : int array_list_del_idx(struct array_list *arr, size_t idx, size_t count)
182 : {
183 : size_t i, stop;
184 :
185 : /* Avoid overflow in calculation with large indices. */
186 0 : if (idx > SIZE_T_MAX - count)
187 0 : return -1;
188 0 : stop = idx + count;
189 0 : if (idx >= arr->length || stop > arr->length)
190 0 : return -1;
191 0 : for (i = idx; i < stop; ++i)
192 : {
193 : // Because put_idx can skip entries, we need to check if
194 : // there's actually anything in each slot we're erasing.
195 0 : if (arr->array[i])
196 0 : arr->free_fn(arr->array[i]);
197 : }
198 0 : memmove(arr->array + idx, arr->array + stop, (arr->length - stop) * sizeof(void *));
199 0 : arr->length -= count;
200 0 : return 0;
201 : }
|