1 /* Sequential list data type implemented by a circular array.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
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 2, or (at your option)
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, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 #include "gl_carray_list.h"
30 /* Checked size_t computations. */
34 # define uintptr_t unsigned long
37 /* -------------------------- gl_list_t Data Type -------------------------- */
39 /* Concrete gl_list_impl type, valid for this file only. */
42 struct gl_list_impl_base base;
43 /* An array of ALLOCATED elements, of which the elements
44 OFFSET, (OFFSET + 1) % ALLOCATED, ..., (OFFSET + COUNT - 1) % ALLOCATED
45 are used. 0 <= COUNT <= ALLOCATED. Either OFFSET = ALLOCATED = 0 or
46 0 <= OFFSET < ALLOCATED. */
47 const void **elements;
53 /* struct gl_list_node_impl doesn't exist here. The pointers are actually
55 #define INDEX_TO_NODE(index) (gl_list_node_t)(uintptr_t)(size_t)((index) + 1)
56 #define NODE_TO_INDEX(node) ((uintptr_t)(node) - 1)
59 gl_carray_create_empty (gl_list_implementation_t implementation,
60 gl_listelement_equals_fn equals_fn,
61 gl_listelement_hashcode_fn hashcode_fn,
62 bool allow_duplicates)
64 struct gl_list_impl *list =
65 (struct gl_list_impl *) xmalloc (sizeof (struct gl_list_impl));
67 list->base.vtable = implementation;
68 list->base.equals_fn = equals_fn;
69 list->base.hashcode_fn = hashcode_fn;
70 list->base.allow_duplicates = allow_duplicates;
71 list->elements = NULL;
80 gl_carray_create (gl_list_implementation_t implementation,
81 gl_listelement_equals_fn equals_fn,
82 gl_listelement_hashcode_fn hashcode_fn,
83 bool allow_duplicates,
84 size_t count, const void **contents)
86 struct gl_list_impl *list =
87 (struct gl_list_impl *) xmalloc (sizeof (struct gl_list_impl));
89 list->base.vtable = implementation;
90 list->base.equals_fn = equals_fn;
91 list->base.hashcode_fn = hashcode_fn;
92 list->base.allow_duplicates = allow_duplicates;
96 (const void **) xmalloc (count * sizeof (const void *));
97 memcpy (list->elements, contents, count * sizeof (const void *));
100 list->elements = NULL;
103 list->allocated = count;
109 gl_carray_size (gl_list_t list)
115 gl_carray_node_value (gl_list_t list, gl_list_node_t node)
117 uintptr_t index = NODE_TO_INDEX (node);
120 if (!(index < list->count))
121 /* Invalid argument. */
123 i = list->offset + index;
124 if (i >= list->allocated)
125 i -= list->allocated;
126 return list->elements[i];
129 static gl_list_node_t
130 gl_carray_next_node (gl_list_t list, gl_list_node_t node)
132 uintptr_t index = NODE_TO_INDEX (node);
133 if (!(index < list->count))
134 /* Invalid argument. */
137 if (index < list->count)
138 return INDEX_TO_NODE (index);
143 static gl_list_node_t
144 gl_carray_previous_node (gl_list_t list, gl_list_node_t node)
146 uintptr_t index = NODE_TO_INDEX (node);
147 if (!(index < list->count))
148 /* Invalid argument. */
151 return INDEX_TO_NODE (index - 1);
157 gl_carray_get_at (gl_list_t list, size_t position)
159 size_t count = list->count;
162 if (!(position < count))
163 /* Invalid argument. */
165 i = list->offset + position;
166 if (i >= list->allocated)
167 i -= list->allocated;
168 return list->elements[i];
171 static gl_list_node_t
172 gl_carray_set_at (gl_list_t list, size_t position, const void *elt)
174 size_t count = list->count;
177 if (!(position < count))
178 /* Invalid argument. */
180 i = list->offset + position;
181 if (i >= list->allocated)
182 i -= list->allocated;
183 list->elements[i] = elt;
184 return INDEX_TO_NODE (position);
188 gl_carray_indexof (gl_list_t list, const void *elt)
190 size_t count = list->count;
193 gl_listelement_equals_fn equals = list->base.equals_fn;
194 size_t allocated = list->allocated;
197 i_end = list->offset + list->count;
198 if (i_end >= allocated)
205 for (i = list->offset;;)
207 if (equals (elt, list->elements[i]))
208 return (i >= list->offset ? i : i + allocated) - list->offset;
220 for (i = list->offset;;)
222 if (elt == list->elements[i])
223 return (i >= list->offset ? i : i + allocated) - list->offset;
235 static gl_list_node_t
236 gl_carray_search (gl_list_t list, const void *elt)
238 size_t index = gl_carray_indexof (list, elt);
239 return INDEX_TO_NODE (index);
242 /* Ensure that list->allocated > list->count. */
244 grow (gl_list_t list)
246 size_t new_allocated;
250 new_allocated = xtimes (list->allocated, 2);
251 new_allocated = xsum (new_allocated, 1);
252 memory_size = xtimes (new_allocated, sizeof (const void *));
253 if (size_overflow_p (memory_size))
254 /* Overflow, would lead to out of memory. */
256 if (list->offset > 0 && list->count > 0)
258 memory = (const void **) xmalloc (memory_size);
262 if (list->offset + list->count > list->allocated)
264 memcpy (memory, &list->elements[list->offset],
265 (list->allocated - list->offset) * sizeof (const void *));
266 memcpy (memory + (list->allocated - list->offset), list->elements,
267 (list->offset + list->count - list->allocated)
268 * sizeof (const void *));
272 memcpy (memory, &list->elements[list->offset],
273 list->count * sizeof (const void *));
274 if (list->elements != NULL)
275 free (list->elements);
279 memory = (const void **) xrealloc (list->elements, memory_size);
284 list->elements = memory;
286 list->allocated = new_allocated;
289 static gl_list_node_t
290 gl_carray_add_first (gl_list_t list, const void *elt)
292 size_t count = list->count;
294 if (count == list->allocated)
296 list->offset = (list->offset == 0 ? list->allocated : list->offset) - 1;
297 list->elements[list->offset] = elt;
298 list->count = count + 1;
299 return INDEX_TO_NODE (0);
302 static gl_list_node_t
303 gl_carray_add_last (gl_list_t list, const void *elt)
305 size_t count = list->count;
308 if (count == list->allocated)
310 i = list->offset + count;
311 if (i >= list->allocated)
312 i -= list->allocated;
313 list->elements[i] = elt;
314 list->count = count + 1;
315 return INDEX_TO_NODE (count);
318 static gl_list_node_t
319 gl_carray_add_at (gl_list_t list, size_t position, const void *elt)
321 size_t count = list->count;
322 const void **elements;
324 if (!(position <= count))
325 /* Invalid argument. */
327 if (count == list->allocated)
329 elements = list->elements;
330 if (position <= (count / 2))
332 /* Shift at most count/2 elements to the left. */
335 list->offset = (list->offset == 0 ? list->allocated : list->offset) - 1;
337 i2 = list->offset + position;
338 if (i2 >= list->allocated)
340 /* Here we must have list->offset > 0, hence list->allocated > 0. */
341 size_t i1 = list->allocated - 1;
342 i2 -= list->allocated;
343 for (i = list->offset; i < i1; i++)
344 elements[i] = elements[i + 1];
345 elements[i1] = elements[0];
346 for (i = 0; i < i2; i++)
347 elements[i] = elements[i + 1];
351 for (i = list->offset; i < i2; i++)
352 elements[i] = elements[i + 1];
358 /* Shift at most (count+1)/2 elements to the right. */
361 i1 = list->offset + position;
362 i3 = list->offset + count;
363 if (i1 >= list->allocated)
365 i1 -= list->allocated;
366 i3 -= list->allocated;
367 for (i = i3; i > i1; i--)
368 elements[i] = elements[i - 1];
370 else if (i3 >= list->allocated)
372 /* Here we must have list->offset > 0, hence list->allocated > 0. */
373 size_t i2 = list->allocated - 1;
374 i3 -= list->allocated;
375 for (i = i3; i > 0; i--)
376 elements[i] = elements[i - 1];
377 elements[0] = elements[i2];
378 for (i = i2; i > i1; i--)
379 elements[i] = elements[i - 1];
383 for (i = i3; i > i1; i--)
384 elements[i] = elements[i - 1];
388 list->count = count + 1;
389 return INDEX_TO_NODE (position);
392 static gl_list_node_t
393 gl_carray_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
395 size_t count = list->count;
396 uintptr_t index = NODE_TO_INDEX (node);
398 if (!(index < count))
399 /* Invalid argument. */
401 return gl_carray_add_at (list, index, elt);
404 static gl_list_node_t
405 gl_carray_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
407 size_t count = list->count;
408 uintptr_t index = NODE_TO_INDEX (node);
410 if (!(index < count))
411 /* Invalid argument. */
413 return gl_carray_add_at (list, index + 1, elt);
417 gl_carray_remove_at (gl_list_t list, size_t position)
419 size_t count = list->count;
420 const void **elements;
422 if (!(position < count))
423 /* Invalid argument. */
425 /* Here we know count > 0. */
426 elements = list->elements;
427 if (position <= ((count - 1) / 2))
429 /* Shift at most (count-1)/2 elements to the right. */
433 i2 = list->offset + position;
434 if (i2 >= list->allocated)
436 /* Here we must have list->offset > 0, hence list->allocated > 0. */
437 size_t i1 = list->allocated - 1;
438 i2 -= list->allocated;
439 for (i = i2; i > 0; i--)
440 elements[i] = elements[i - 1];
441 elements[0] = elements[i1];
442 for (i = i1; i > i0; i--)
443 elements[i] = elements[i - 1];
447 for (i = i2; i > i0; i--)
448 elements[i] = elements[i - 1];
452 list->offset = (i0 == list->allocated ? 0 : i0);
456 /* Shift at most count/2 elements to the left. */
459 i1 = list->offset + position;
460 i3 = list->offset + count - 1;
461 if (i1 >= list->allocated)
463 i1 -= list->allocated;
464 i3 -= list->allocated;
465 for (i = i1; i < i3; i++)
466 elements[i] = elements[i + 1];
468 else if (i3 >= list->allocated)
470 /* Here we must have list->offset > 0, hence list->allocated > 0. */
471 size_t i2 = list->allocated - 1;
472 i3 -= list->allocated;
473 for (i = i1; i < i2; i++)
474 elements[i] = elements[i + 1];
475 elements[i2] = elements[0];
476 for (i = 0; i < i3; i++)
477 elements[i] = elements[i + 1];
481 for (i = i1; i < i3; i++)
482 elements[i] = elements[i + 1];
485 list->count = count - 1;
490 gl_carray_remove_node (gl_list_t list, gl_list_node_t node)
492 size_t count = list->count;
493 uintptr_t index = NODE_TO_INDEX (node);
495 if (!(index < count))
496 /* Invalid argument. */
498 return gl_carray_remove_at (list, index);
502 gl_carray_remove (gl_list_t list, const void *elt)
504 size_t position = gl_carray_indexof (list, elt);
505 if (position == (size_t)(-1))
508 return gl_carray_remove_at (list, position);
512 gl_carray_list_free (gl_list_t list)
514 if (list->elements != NULL)
515 free (list->elements);
519 /* --------------------- gl_list_iterator_t Data Type --------------------- */
521 static gl_list_iterator_t
522 gl_carray_iterator (gl_list_t list)
524 gl_list_iterator_t result;
526 result.vtable = list->base.vtable;
528 result.count = list->count;
530 result.j = list->count;
535 static gl_list_iterator_t
536 gl_carray_iterator_from_to (gl_list_t list, size_t start_index, size_t end_index)
538 gl_list_iterator_t result;
540 if (!(start_index <= end_index && end_index <= list->count))
541 /* Invalid arguments. */
543 result.vtable = list->base.vtable;
545 result.count = list->count;
546 result.i = start_index;
547 result.j = end_index;
553 gl_carray_iterator_next (gl_list_iterator_t *iterator,
554 const void **eltp, gl_list_node_t *nodep)
556 gl_list_t list = iterator->list;
557 if (iterator->count != list->count)
559 if (iterator->count != list->count + 1)
560 /* Concurrent modifications were done on the list. */
562 /* The last returned element was removed. */
567 if (iterator->i < iterator->j)
569 size_t i = list->offset + iterator->i;
570 if (i >= list->allocated)
571 i -= list->allocated;
572 *eltp = list->elements[i];
574 *nodep = INDEX_TO_NODE (iterator->i);
583 gl_carray_iterator_free (gl_list_iterator_t *iterator)
587 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
590 gl_carray_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
593 size_t count = list->count;
600 /* At each loop iteration, low < high; for indices < low the values
601 are smaller than ELT; for indices >= high the values are greater
602 than ELT. So, if the element occurs in the list, is at
603 low <= position < high. */
606 size_t mid = low + (high - low) / 2; /* low <= mid < high */
610 i_mid = list->offset + mid;
611 if (i_mid >= list->allocated)
612 i_mid -= list->allocated;
614 cmp = compar (list->elements[i_mid], elt);
622 /* We have an element equal to ELT at index MID. But we need
623 the minimal such index. */
625 /* At each loop iteration, low <= high and
626 compar (list->elements[i_high], elt) == 0,
627 and we know that the first occurrence of the element is at
628 low <= position <= high. */
631 size_t mid2 = low + (high - low) / 2; /* low <= mid < high */
635 i_mid2 = list->offset + mid2;
636 if (i_mid2 >= list->allocated)
637 i_mid2 -= list->allocated;
639 cmp2 = compar (list->elements[i_mid2], elt);
644 /* The list was not sorted. */
657 /* Here low == high. */
662 static gl_list_node_t
663 gl_carray_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
666 size_t index = gl_carray_sortedlist_indexof (list, compar, elt);
667 return INDEX_TO_NODE (index);
670 static gl_list_node_t
671 gl_carray_sortedlist_add (gl_list_t list, gl_listelement_compar_fn compar,
674 size_t count = list->count;
678 /* At each loop iteration, low <= high; for indices < low the values are
679 smaller than ELT; for indices >= high the values are greater than ELT. */
682 size_t mid = low + (high - low) / 2; /* low <= mid < high */
686 i_mid = list->offset + mid;
687 if (i_mid >= list->allocated)
688 i_mid -= list->allocated;
690 cmp = compar (list->elements[i_mid], elt);
702 return gl_carray_add_at (list, low, elt);
706 gl_carray_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
709 size_t index = gl_carray_sortedlist_indexof (list, compar, elt);
710 if (index == (size_t)(-1))
713 return gl_carray_remove_at (list, index);
717 const struct gl_list_implementation gl_carray_list_implementation =
719 gl_carray_create_empty,
722 gl_carray_node_value,
724 gl_carray_previous_node,
731 gl_carray_add_before,
734 gl_carray_remove_node,
739 gl_carray_iterator_from_to,
740 gl_carray_iterator_next,
741 gl_carray_iterator_free,
742 gl_carray_sortedlist_search,
743 gl_carray_sortedlist_indexof,
744 gl_carray_sortedlist_add,
745 gl_carray_sortedlist_remove