exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / gl_array_omap.c
blob8a4906fe83f43ab83352623587653b3efb0f9d23
1 /* Ordered map data type implemented by an array.
2 Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2018.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "gl_array_omap.h"
23 #include <stdlib.h>
25 /* Checked size_t computations. */
26 #include "xsize.h"
28 /* -------------------------- gl_omap_t Data Type -------------------------- */
30 struct pair
32 const void *key;
33 const void *value;
36 /* Concrete gl_omap_impl type, valid for this file only. */
37 struct gl_omap_impl
39 struct gl_omap_impl_base base;
40 /* An array of ALLOCATED pairs, of which the first COUNT are used.
41 0 <= COUNT <= ALLOCATED. */
42 struct pair *pairs;
43 size_t count;
44 size_t allocated;
47 static gl_omap_t
48 gl_array_nx_create_empty (gl_omap_implementation_t implementation,
49 gl_mapkey_compar_fn compar_fn,
50 gl_mapkey_dispose_fn kdispose_fn,
51 gl_mapvalue_dispose_fn vdispose_fn)
53 struct gl_omap_impl *map =
54 (struct gl_omap_impl *) malloc (sizeof (struct gl_omap_impl));
56 if (map == NULL)
57 return NULL;
59 map->base.vtable = implementation;
60 map->base.compar_fn = compar_fn;
61 map->base.kdispose_fn = kdispose_fn;
62 map->base.vdispose_fn = vdispose_fn;
63 map->pairs = NULL;
64 map->count = 0;
65 map->allocated = 0;
67 return map;
70 static size_t _GL_ATTRIBUTE_PURE
71 gl_array_size (gl_omap_t map)
73 return map->count;
76 static size_t _GL_ATTRIBUTE_PURE
77 gl_array_indexof (gl_omap_t map, const void *key)
79 size_t count = map->count;
81 if (count > 0)
83 gl_mapkey_compar_fn compar = map->base.compar_fn;
84 size_t low = 0;
85 size_t high = count;
87 /* At each loop iteration, low < high; for indices < low the values
88 are smaller than KEY; for indices >= high the values are greater
89 than KEY. So, if the key occurs in the map, it is at
90 low <= position < high. */
93 size_t mid = low + (high - low) / 2; /* low <= mid < high */
94 int cmp = (compar != NULL
95 ? compar (map->pairs[mid].key, key)
96 : (map->pairs[mid].key > key ? 1 :
97 map->pairs[mid].key < key ? -1 : 0));
99 if (cmp < 0)
100 low = mid + 1;
101 else if (cmp > 0)
102 high = mid;
103 else /* cmp == 0 */
104 /* We have a key equal to KEY at index MID. */
105 return mid;
107 while (low < high);
109 return (size_t)(-1);
112 static bool _GL_ATTRIBUTE_PURE
113 gl_array_search (gl_omap_t map, const void *key, const void **valuep)
115 size_t index = gl_array_indexof (map, key);
116 if (index != (size_t)(-1))
118 *valuep = map->pairs[index].value;
119 return true;
121 else
122 return false;
125 static bool _GL_ATTRIBUTE_PURE
126 gl_array_search_atleast (gl_omap_t map,
127 gl_mapkey_threshold_fn threshold_fn,
128 const void *threshold,
129 const void **keyp, const void **valuep)
131 size_t count = map->count;
133 if (count > 0)
135 size_t low = 0;
136 size_t high = count;
138 /* At each loop iteration, low < high; for indices < low the values are
139 smaller than THRESHOLD; for indices >= high the values are nonexistent.
140 So, if a key >= THRESHOLD occurs in the map, it is at
141 low <= position < high. */
144 size_t mid = low + (high - low) / 2; /* low <= mid < high */
146 if (! threshold_fn (map->pairs[mid].key, threshold))
147 low = mid + 1;
148 else
150 /* We have a key >= THRESHOLD at index MID. But we need the
151 minimal such index. */
152 high = mid;
153 /* At each loop iteration, low <= high and
154 compar (map->pairs[high].key, value) >= 0,
155 and we know that the first occurrence of the key is at
156 low <= position <= high. */
157 while (low < high)
159 size_t mid2 = low + (high - low) / 2; /* low <= mid2 < high */
161 if (! threshold_fn (map->pairs[mid2].key, threshold))
162 low = mid2 + 1;
163 else
164 high = mid2;
166 *keyp = map->pairs[low].key;
167 *valuep = map->pairs[low].value;
168 return true;
171 while (low < high);
173 return false;
176 /* Ensure that map->allocated > map->count.
177 Return 0 upon success, -1 upon out-of-memory. */
178 static int
179 grow (gl_omap_t map)
181 size_t new_allocated;
182 size_t memory_size;
183 struct pair *memory;
185 new_allocated = xtimes (map->allocated, 2);
186 new_allocated = xsum (new_allocated, 1);
187 memory_size = xtimes (new_allocated, sizeof (struct pair));
188 if (size_overflow_p (memory_size))
189 /* Overflow, would lead to out of memory. */
190 return -1;
191 memory = (struct pair *) realloc (map->pairs, memory_size);
192 if (memory == NULL)
193 /* Out of memory. */
194 return -1;
195 map->pairs = memory;
196 map->allocated = new_allocated;
197 return 0;
200 /* Add the given pair (KEY, VALUE) at the given position,
201 0 <= position <= gl_omap_size (map).
202 Return 1 upon success, -1 upon out-of-memory. */
203 static int
204 gl_array_nx_add_at (gl_omap_t map, size_t position,
205 const void *key, const void *value)
207 size_t count = map->count;
208 struct pair *pairs;
209 size_t i;
211 if (count == map->allocated)
212 if (grow (map) < 0)
213 return -1;
214 pairs = map->pairs;
215 for (i = count; i > position; i--)
216 pairs[i] = pairs[i - 1];
217 pairs[position].key = key;
218 pairs[position].value = value;
219 map->count = count + 1;
220 return 1;
223 static int
224 gl_array_nx_getput (gl_omap_t map, const void *key, const void *value,
225 const void **oldvaluep)
227 size_t count = map->count;
228 size_t low = 0;
230 if (count > 0)
232 gl_mapkey_compar_fn compar = map->base.compar_fn;
233 size_t high = count;
235 /* At each loop iteration, low < high; for indices < low the keys
236 are smaller than KEY; for indices >= high the keys are greater
237 than KEY. So, if the key occurs in the map, it is at
238 low <= position < high. */
241 size_t mid = low + (high - low) / 2; /* low <= mid < high */
242 int cmp = (compar != NULL
243 ? compar (map->pairs[mid].key, key)
244 : (map->pairs[mid].key > key ? 1 :
245 map->pairs[mid].key < key ? -1 : 0));
247 if (cmp < 0)
248 low = mid + 1;
249 else if (cmp > 0)
250 high = mid;
251 else /* cmp == 0 */
253 *oldvaluep = map->pairs[mid].value;
254 map->pairs[mid].value = value;
255 return 0;
258 while (low < high);
260 return gl_array_nx_add_at (map, low, key, value);
263 /* Remove the pair at the given position,
264 0 <= position < gl_omap_size (map). */
265 static void
266 gl_array_remove_at (gl_omap_t map, size_t position)
268 size_t count = map->count;
269 struct pair *pairs;
270 size_t i;
272 pairs = map->pairs;
273 if (map->base.kdispose_fn != NULL)
274 map->base.kdispose_fn (pairs[position].key);
275 for (i = position + 1; i < count; i++)
276 pairs[i - 1] = pairs[i];
277 map->count = count - 1;
280 static bool
281 gl_array_getremove (gl_omap_t map, const void *key, const void **oldvaluep)
283 size_t index = gl_array_indexof (map, key);
284 if (index != (size_t)(-1))
286 *oldvaluep = map->pairs[index].value;
287 gl_array_remove_at (map, index);
288 return true;
290 else
291 return false;
294 static void
295 gl_array_free (gl_omap_t map)
297 if (map->pairs != NULL)
299 if (map->base.kdispose_fn != NULL || map->base.vdispose_fn != NULL)
301 size_t count = map->count;
303 if (count > 0)
305 gl_mapkey_dispose_fn kdispose = map->base.kdispose_fn;
306 gl_mapvalue_dispose_fn vdispose = map->base.vdispose_fn;
307 struct pair *pairs = map->pairs;
311 if (vdispose)
312 vdispose (pairs->value);
313 if (kdispose)
314 kdispose (pairs->key);
315 pairs++;
317 while (--count > 0);
320 free (map->pairs);
322 free (map);
325 /* ---------------------- gl_omap_iterator_t Data Type ---------------------- */
327 static gl_omap_iterator_t _GL_ATTRIBUTE_PURE
328 gl_array_iterator (gl_omap_t map)
330 gl_omap_iterator_t result;
332 result.vtable = map->base.vtable;
333 result.map = map;
334 result.count = map->count;
335 result.p = map->pairs + 0;
336 result.q = map->pairs + map->count;
337 #if defined GCC_LINT || defined lint
338 result.i = 0;
339 result.j = 0;
340 #endif
342 return result;
345 static bool
346 gl_array_iterator_next (gl_omap_iterator_t *iterator,
347 const void **keyp, const void **valuep)
349 gl_omap_t map = iterator->map;
350 if (iterator->count != map->count)
352 if (iterator->count != map->count + 1)
353 /* Concurrent modifications were done on the map. */
354 abort ();
355 /* The last returned pair was removed. */
356 iterator->count--;
357 iterator->p = (struct pair *) iterator->p - 1;
358 iterator->q = (struct pair *) iterator->q - 1;
360 if (iterator->p < iterator->q)
362 struct pair *p = (struct pair *) iterator->p;
363 *keyp = p->key;
364 *valuep = p->value;
365 iterator->p = p + 1;
366 return true;
368 else
369 return false;
372 static void
373 gl_array_iterator_free (_GL_ATTRIBUTE_MAYBE_UNUSED gl_omap_iterator_t *iterator)
378 const struct gl_omap_implementation gl_array_omap_implementation =
380 gl_array_nx_create_empty,
381 gl_array_size,
382 gl_array_search,
383 gl_array_search_atleast,
384 gl_array_nx_getput,
385 gl_array_getremove,
386 gl_array_free,
387 gl_array_iterator,
388 gl_array_iterator_next,
389 gl_array_iterator_free