1 /* Ordered map data type implemented by an array.
2 Copyright (C) 2006-2007, 2009-2021 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2018.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include "gl_array_omap.h"
25 /* Checked size_t computations. */
28 /* -------------------------- gl_omap_t Data Type -------------------------- */
36 /* Concrete gl_omap_impl type, valid for this file only. */
39 struct gl_omap_impl_base base
;
40 /* An array of ALLOCATED pairs, of which the first COUNT are used.
41 0 <= COUNT <= ALLOCATED. */
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
));
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
;
70 static size_t _GL_ATTRIBUTE_PURE
71 gl_array_size (gl_omap_t map
)
76 static size_t _GL_ATTRIBUTE_PURE
77 gl_array_indexof (gl_omap_t map
, const void *key
)
79 size_t count
= map
->count
;
83 gl_mapkey_compar_fn compar
= map
->base
.compar_fn
;
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));
104 /* We have a key equal to KEY at index MID. */
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
;
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
;
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
))
150 /* We have a key >= THRESHOLD at index MID. But we need the
151 minimal such index. */
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. */
159 size_t mid2
= low
+ (high
- low
) / 2; /* low <= mid2 < high */
161 if (! threshold_fn (map
->pairs
[mid2
].key
, threshold
))
166 *keyp
= map
->pairs
[low
].key
;
167 *valuep
= map
->pairs
[low
].value
;
176 /* Ensure that map->allocated > map->count.
177 Return 0 upon success, -1 upon out-of-memory. */
181 size_t new_allocated
;
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. */
191 memory
= (struct pair
*) realloc (map
->pairs
, memory_size
);
196 map
->allocated
= new_allocated
;
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. */
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
;
211 if (count
== map
->allocated
)
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;
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
;
232 gl_mapkey_compar_fn compar
= map
->base
.compar_fn
;
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));
253 *oldvaluep
= map
->pairs
[mid
].value
;
254 map
->pairs
[mid
].value
= value
;
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). */
266 gl_array_remove_at (gl_omap_t map
, size_t position
)
268 size_t count
= map
->count
;
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;
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
);
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
;
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
;
312 vdispose (pairs
->value
);
314 kdispose (pairs
->key
);
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
;
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
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. */
355 /* The last returned pair was removed. */
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
;
373 gl_array_iterator_free (gl_omap_iterator_t
*iterator _GL_ATTRIBUTE_MAYBE_UNUSED
)
378 const struct gl_omap_implementation gl_array_omap_implementation
=
380 gl_array_nx_create_empty
,
383 gl_array_search_atleast
,
388 gl_array_iterator_next
,
389 gl_array_iterator_free