1 /* Ordered set 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>, 2006.
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/>. */
21 #include "gl_array_oset.h"
25 /* Checked size_t computations. */
28 /* -------------------------- gl_oset_t Data Type -------------------------- */
30 /* Concrete gl_oset_impl type, valid for this file only. */
33 struct gl_oset_impl_base base
;
34 /* An array of ALLOCATED elements, of which the first COUNT are used.
35 0 <= COUNT <= ALLOCATED. */
36 const void **elements
;
42 gl_array_nx_create_empty (gl_oset_implementation_t implementation
,
43 gl_setelement_compar_fn compar_fn
,
44 gl_setelement_dispose_fn dispose_fn
)
46 struct gl_oset_impl
*set
=
47 (struct gl_oset_impl
*) malloc (sizeof (struct gl_oset_impl
));
52 set
->base
.vtable
= implementation
;
53 set
->base
.compar_fn
= compar_fn
;
54 set
->base
.dispose_fn
= dispose_fn
;
62 static size_t _GL_ATTRIBUTE_PURE
63 gl_array_size (gl_oset_t set
)
68 static size_t _GL_ATTRIBUTE_PURE
69 gl_array_indexof (gl_oset_t set
, const void *elt
)
71 size_t count
= set
->count
;
75 gl_setelement_compar_fn compar
= set
->base
.compar_fn
;
79 /* At each loop iteration, low < high; for indices < low the values
80 are smaller than ELT; for indices >= high the values are greater
81 than ELT. So, if the element occurs in the list, it is at
82 low <= position < high. */
85 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
86 int cmp
= (compar
!= NULL
87 ? compar (set
->elements
[mid
], elt
)
88 : (set
->elements
[mid
] > elt
? 1 :
89 set
->elements
[mid
] < elt
? -1 : 0));
96 /* We have an element equal to ELT at index MID. */
104 static bool _GL_ATTRIBUTE_PURE
105 gl_array_search (gl_oset_t set
, const void *elt
)
107 return gl_array_indexof (set
, elt
) != (size_t)(-1);
110 /* Searches the least element in the ordered set that compares greater or equal
111 to the given THRESHOLD. The representation of the THRESHOLD is defined
113 Returns the position at which it was found, or gl_list_size (SET) if not
115 static size_t _GL_ATTRIBUTE_PURE
116 gl_array_indexof_atleast (gl_oset_t set
,
117 gl_setelement_threshold_fn threshold_fn
,
118 const void *threshold
)
120 size_t count
= set
->count
;
127 /* At each loop iteration, low < high; for indices < low the values are
128 smaller than THRESHOLD; for indices >= high the values are nonexistent.
129 So, if an element >= THRESHOLD occurs in the list, it is at
130 low <= position < high. */
133 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
135 if (! threshold_fn (set
->elements
[mid
], threshold
))
139 /* We have an element >= THRESHOLD at index MID. But we need the
140 minimal such index. */
142 /* At each loop iteration, low <= high and
143 compar (set->elements[high], threshold) >= 0,
144 and we know that the first occurrence of the element is at
145 low <= position <= high. */
148 size_t mid2
= low
+ (high
- low
) / 2; /* low <= mid2 < high */
150 if (! threshold_fn (set
->elements
[mid2
], threshold
))
163 static bool _GL_ATTRIBUTE_PURE
164 gl_array_search_atleast (gl_oset_t set
,
165 gl_setelement_threshold_fn threshold_fn
,
166 const void *threshold
,
169 size_t index
= gl_array_indexof_atleast (set
, threshold_fn
, threshold
);
171 if (index
== set
->count
)
175 *eltp
= set
->elements
[index
];
180 /* Ensure that set->allocated > set->count.
181 Return 0 upon success, -1 upon out-of-memory. */
185 size_t new_allocated
;
189 new_allocated
= xtimes (set
->allocated
, 2);
190 new_allocated
= xsum (new_allocated
, 1);
191 memory_size
= xtimes (new_allocated
, sizeof (const void *));
192 if (size_overflow_p (memory_size
))
193 /* Overflow, would lead to out of memory. */
195 memory
= (const void **) realloc (set
->elements
, memory_size
);
199 set
->elements
= memory
;
200 set
->allocated
= new_allocated
;
204 /* Add the given element ELT at the given position,
205 0 <= position <= gl_oset_size (set).
206 Return 1 upon success, -1 upon out-of-memory. */
208 gl_array_nx_add_at (gl_oset_t set
, size_t position
, const void *elt
)
210 size_t count
= set
->count
;
211 const void **elements
;
214 if (count
== set
->allocated
)
217 elements
= set
->elements
;
218 for (i
= count
; i
> position
; i
--)
219 elements
[i
] = elements
[i
- 1];
220 elements
[position
] = elt
;
221 set
->count
= count
+ 1;
225 /* Remove the element at the given position,
226 0 <= position < gl_oset_size (set). */
228 gl_array_remove_at (gl_oset_t set
, size_t position
)
230 size_t count
= set
->count
;
231 const void **elements
;
234 elements
= set
->elements
;
235 if (set
->base
.dispose_fn
!= NULL
)
236 set
->base
.dispose_fn (elements
[position
]);
237 for (i
= position
+ 1; i
< count
; i
++)
238 elements
[i
- 1] = elements
[i
];
239 set
->count
= count
- 1;
243 gl_array_nx_add (gl_oset_t set
, const void *elt
)
245 size_t count
= set
->count
;
250 gl_setelement_compar_fn compar
= set
->base
.compar_fn
;
253 /* At each loop iteration, low < high; for indices < low the values
254 are smaller than ELT; for indices >= high the values are greater
255 than ELT. So, if the element occurs in the list, it is at
256 low <= position < high. */
259 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
260 int cmp
= (compar
!= NULL
261 ? compar (set
->elements
[mid
], elt
)
262 : (set
->elements
[mid
] > elt
? 1 :
263 set
->elements
[mid
] < elt
? -1 : 0));
274 return gl_array_nx_add_at (set
, low
, elt
);
278 gl_array_remove (gl_oset_t set
, const void *elt
)
280 size_t index
= gl_array_indexof (set
, elt
);
281 if (index
!= (size_t)(-1))
283 gl_array_remove_at (set
, index
);
291 gl_array_update (gl_oset_t set
, const void *elt
,
292 void (*action
) (const void * /*elt*/, void * /*action_data*/),
295 /* Like gl_array_remove, action (...), gl_array_nx_add, except that we don't
296 actually remove ELT. */
297 /* Remember the old position. */
298 size_t old_index
= gl_array_indexof (set
, elt
);
300 action (elt
, action_data
);
301 /* Determine the new position. */
302 if (old_index
!= (size_t)(-1))
304 size_t count
= set
->count
;
308 gl_setelement_compar_fn compar
= set
->base
.compar_fn
;
314 size_t mid
= old_index
- 1;
315 int cmp
= (compar
!= NULL
316 ? compar (set
->elements
[mid
], elt
)
317 : (set
->elements
[mid
] > elt
? 1 :
318 set
->elements
[mid
] < elt
? -1 : 0));
331 /* Two adjacent elements are the same. */
332 gl_array_remove_at (set
, old_index
);
342 /* At each loop iteration, low <= high; for indices < low the values
343 are smaller than ELT; for indices >= high the values are greater
344 than ELT. So, if the element occurs in the list, it is at
345 low <= position < high. */
348 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
349 int cmp
= (compar
!= NULL
350 ? compar (set
->elements
[mid
], elt
)
351 : (set
->elements
[mid
] > elt
? 1 :
352 set
->elements
[mid
] < elt
? -1 : 0));
360 /* Two elements are the same. */
361 gl_array_remove_at (set
, old_index
);
368 /* Move the element from old_index to low. */
369 size_t new_index
= low
;
370 const void **elements
= set
->elements
;
373 for (i
= old_index
; i
> new_index
; i
--)
374 elements
[i
] = elements
[i
- 1];
375 elements
[new_index
] = elt
;
380 /* low > old_index. */
381 /* Move the element from old_index to low - 1. */
382 size_t new_index
= low
- 1;
384 if (new_index
> old_index
)
386 const void **elements
= set
->elements
;
389 for (i
= old_index
; i
< new_index
; i
++)
390 elements
[i
] = elements
[i
+ 1];
391 elements
[new_index
] = elt
;
401 gl_array_free (gl_oset_t set
)
403 if (set
->elements
!= NULL
)
405 if (set
->base
.dispose_fn
!= NULL
)
407 size_t count
= set
->count
;
411 gl_setelement_dispose_fn dispose
= set
->base
.dispose_fn
;
412 const void **elements
= set
->elements
;
415 dispose (*elements
++);
419 free (set
->elements
);
424 /* --------------------- gl_oset_iterator_t Data Type --------------------- */
426 static gl_oset_iterator_t _GL_ATTRIBUTE_PURE
427 gl_array_iterator (gl_oset_t set
)
429 gl_oset_iterator_t result
;
431 result
.vtable
= set
->base
.vtable
;
433 result
.count
= set
->count
;
434 result
.p
= set
->elements
+ 0;
435 result
.q
= set
->elements
+ set
->count
;
436 #if defined GCC_LINT || defined lint
444 static gl_oset_iterator_t _GL_ATTRIBUTE_PURE
445 gl_array_iterator_atleast (gl_oset_t set
,
446 gl_setelement_threshold_fn threshold_fn
,
447 const void *threshold
)
449 size_t index
= gl_array_indexof_atleast (set
, threshold_fn
, threshold
);
450 gl_oset_iterator_t result
;
452 result
.vtable
= set
->base
.vtable
;
454 result
.count
= set
->count
;
455 result
.p
= set
->elements
+ index
;
456 result
.q
= set
->elements
+ set
->count
;
457 #if defined GCC_LINT || defined lint
466 gl_array_iterator_next (gl_oset_iterator_t
*iterator
, const void **eltp
)
468 gl_oset_t set
= iterator
->set
;
469 if (iterator
->count
!= set
->count
)
471 if (iterator
->count
!= set
->count
+ 1)
472 /* Concurrent modifications were done on the set. */
474 /* The last returned element was removed. */
476 iterator
->p
= (const void **) iterator
->p
- 1;
477 iterator
->q
= (const void **) iterator
->q
- 1;
479 if (iterator
->p
< iterator
->q
)
481 const void **p
= (const void **) iterator
->p
;
491 gl_array_iterator_free (_GL_ATTRIBUTE_MAYBE_UNUSED gl_oset_iterator_t
*iterator
)
496 const struct gl_oset_implementation gl_array_oset_implementation
=
498 gl_array_nx_create_empty
,
501 gl_array_search_atleast
,
507 gl_array_iterator_atleast
,
508 gl_array_iterator_next
,
509 gl_array_iterator_free