1 /* Sequential list data type implemented by an array.
2 Copyright (C) 2006-2018 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 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_list.h"
27 /* Checked size_t computations. */
31 # define uintptr_t unsigned long
34 /* -------------------------- gl_list_t Data Type -------------------------- */
36 /* Concrete gl_list_impl type, valid for this file only. */
39 struct gl_list_impl_base base
;
40 /* An array of ALLOCATED elements, of which the first COUNT are used.
41 0 <= COUNT <= ALLOCATED. */
42 const void **elements
;
47 /* struct gl_list_node_impl doesn't exist here. The pointers are actually
49 #define INDEX_TO_NODE(index) (gl_list_node_t)(uintptr_t)(size_t)((index) + 1)
50 #define NODE_TO_INDEX(node) ((uintptr_t)(node) - 1)
53 gl_array_nx_create_empty (gl_list_implementation_t implementation
,
54 gl_listelement_equals_fn equals_fn
,
55 gl_listelement_hashcode_fn hashcode_fn
,
56 gl_listelement_dispose_fn dispose_fn
,
57 bool allow_duplicates
)
59 struct gl_list_impl
*list
=
60 (struct gl_list_impl
*) malloc (sizeof (struct gl_list_impl
));
65 list
->base
.vtable
= implementation
;
66 list
->base
.equals_fn
= equals_fn
;
67 list
->base
.hashcode_fn
= hashcode_fn
;
68 list
->base
.dispose_fn
= dispose_fn
;
69 list
->base
.allow_duplicates
= allow_duplicates
;
70 list
->elements
= NULL
;
78 gl_array_nx_create (gl_list_implementation_t implementation
,
79 gl_listelement_equals_fn equals_fn
,
80 gl_listelement_hashcode_fn hashcode_fn
,
81 gl_listelement_dispose_fn dispose_fn
,
82 bool allow_duplicates
,
83 size_t count
, const void **contents
)
85 struct gl_list_impl
*list
=
86 (struct gl_list_impl
*) malloc (sizeof (struct gl_list_impl
));
91 list
->base
.vtable
= implementation
;
92 list
->base
.equals_fn
= equals_fn
;
93 list
->base
.hashcode_fn
= hashcode_fn
;
94 list
->base
.dispose_fn
= dispose_fn
;
95 list
->base
.allow_duplicates
= allow_duplicates
;
98 if (size_overflow_p (xtimes (count
, sizeof (const void *))))
100 list
->elements
= (const void **) malloc (count
* sizeof (const void *));
101 if (list
->elements
== NULL
)
103 memcpy (list
->elements
, contents
, count
* sizeof (const void *));
106 list
->elements
= NULL
;
108 list
->allocated
= count
;
118 gl_array_size (gl_list_t list
)
123 static const void * _GL_ATTRIBUTE_PURE
124 gl_array_node_value (gl_list_t list
, gl_list_node_t node
)
126 uintptr_t index
= NODE_TO_INDEX (node
);
127 if (!(index
< list
->count
))
128 /* Invalid argument. */
130 return list
->elements
[index
];
134 gl_array_node_nx_set_value (gl_list_t list
, gl_list_node_t node
,
137 uintptr_t index
= NODE_TO_INDEX (node
);
138 if (!(index
< list
->count
))
139 /* Invalid argument. */
141 list
->elements
[index
] = elt
;
145 static gl_list_node_t _GL_ATTRIBUTE_PURE
146 gl_array_next_node (gl_list_t list
, gl_list_node_t node
)
148 uintptr_t index
= NODE_TO_INDEX (node
);
149 if (!(index
< list
->count
))
150 /* Invalid argument. */
153 if (index
< list
->count
)
154 return INDEX_TO_NODE (index
);
159 static gl_list_node_t _GL_ATTRIBUTE_PURE
160 gl_array_previous_node (gl_list_t list
, gl_list_node_t node
)
162 uintptr_t index
= NODE_TO_INDEX (node
);
163 if (!(index
< list
->count
))
164 /* Invalid argument. */
167 return INDEX_TO_NODE (index
- 1);
172 static const void * _GL_ATTRIBUTE_PURE
173 gl_array_get_at (gl_list_t list
, size_t position
)
175 size_t count
= list
->count
;
177 if (!(position
< count
))
178 /* Invalid argument. */
180 return list
->elements
[position
];
183 static gl_list_node_t
184 gl_array_nx_set_at (gl_list_t list
, size_t position
, const void *elt
)
186 size_t count
= list
->count
;
188 if (!(position
< count
))
189 /* Invalid argument. */
191 list
->elements
[position
] = elt
;
192 return INDEX_TO_NODE (position
);
196 gl_array_indexof_from_to (gl_list_t list
, size_t start_index
, size_t end_index
,
199 size_t count
= list
->count
;
201 if (!(start_index
<= end_index
&& end_index
<= count
))
202 /* Invalid arguments. */
205 if (start_index
< end_index
)
207 gl_listelement_equals_fn equals
= list
->base
.equals_fn
;
212 for (i
= start_index
;;)
214 if (equals (elt
, list
->elements
[i
]))
225 for (i
= start_index
;;)
227 if (elt
== list
->elements
[i
])
238 static gl_list_node_t
239 gl_array_search_from_to (gl_list_t list
, size_t start_index
, size_t end_index
,
242 size_t index
= gl_array_indexof_from_to (list
, start_index
, end_index
, elt
);
243 return INDEX_TO_NODE (index
);
246 /* Ensure that list->allocated > list->count.
247 Return 0 upon success, -1 upon out-of-memory. */
249 grow (gl_list_t list
)
251 size_t new_allocated
;
255 new_allocated
= xtimes (list
->allocated
, 2);
256 new_allocated
= xsum (new_allocated
, 1);
257 memory_size
= xtimes (new_allocated
, sizeof (const void *));
258 if (size_overflow_p (memory_size
))
259 /* Overflow, would lead to out of memory. */
261 memory
= (const void **) realloc (list
->elements
, memory_size
);
265 list
->elements
= memory
;
266 list
->allocated
= new_allocated
;
270 static gl_list_node_t
271 gl_array_nx_add_first (gl_list_t list
, const void *elt
)
273 size_t count
= list
->count
;
274 const void **elements
;
277 if (count
== list
->allocated
)
280 elements
= list
->elements
;
281 for (i
= count
; i
> 0; i
--)
282 elements
[i
] = elements
[i
- 1];
284 list
->count
= count
+ 1;
285 return INDEX_TO_NODE (0);
288 static gl_list_node_t
289 gl_array_nx_add_last (gl_list_t list
, const void *elt
)
291 size_t count
= list
->count
;
293 if (count
== list
->allocated
)
296 list
->elements
[count
] = elt
;
297 list
->count
= count
+ 1;
298 return INDEX_TO_NODE (count
);
301 static gl_list_node_t
302 gl_array_nx_add_before (gl_list_t list
, gl_list_node_t node
, const void *elt
)
304 size_t count
= list
->count
;
305 uintptr_t index
= NODE_TO_INDEX (node
);
307 const void **elements
;
310 if (!(index
< count
))
311 /* Invalid argument. */
314 if (count
== list
->allocated
)
317 elements
= list
->elements
;
318 for (i
= count
; i
> position
; i
--)
319 elements
[i
] = elements
[i
- 1];
320 elements
[position
] = elt
;
321 list
->count
= count
+ 1;
322 return INDEX_TO_NODE (position
);
325 static gl_list_node_t
326 gl_array_nx_add_after (gl_list_t list
, gl_list_node_t node
, const void *elt
)
328 size_t count
= list
->count
;
329 uintptr_t index
= NODE_TO_INDEX (node
);
331 const void **elements
;
334 if (!(index
< count
))
335 /* Invalid argument. */
337 position
= index
+ 1;
338 if (count
== list
->allocated
)
341 elements
= list
->elements
;
342 for (i
= count
; i
> position
; i
--)
343 elements
[i
] = elements
[i
- 1];
344 elements
[position
] = elt
;
345 list
->count
= count
+ 1;
346 return INDEX_TO_NODE (position
);
349 static gl_list_node_t
350 gl_array_nx_add_at (gl_list_t list
, size_t position
, const void *elt
)
352 size_t count
= list
->count
;
353 const void **elements
;
356 if (!(position
<= count
))
357 /* Invalid argument. */
359 if (count
== list
->allocated
)
362 elements
= list
->elements
;
363 for (i
= count
; i
> position
; i
--)
364 elements
[i
] = elements
[i
- 1];
365 elements
[position
] = elt
;
366 list
->count
= count
+ 1;
367 return INDEX_TO_NODE (position
);
371 gl_array_remove_node (gl_list_t list
, gl_list_node_t node
)
373 size_t count
= list
->count
;
374 uintptr_t index
= NODE_TO_INDEX (node
);
376 const void **elements
;
379 if (!(index
< count
))
380 /* Invalid argument. */
383 elements
= list
->elements
;
384 if (list
->base
.dispose_fn
!= NULL
)
385 list
->base
.dispose_fn (elements
[position
]);
386 for (i
= position
+ 1; i
< count
; i
++)
387 elements
[i
- 1] = elements
[i
];
388 list
->count
= count
- 1;
393 gl_array_remove_at (gl_list_t list
, size_t position
)
395 size_t count
= list
->count
;
396 const void **elements
;
399 if (!(position
< count
))
400 /* Invalid argument. */
402 elements
= list
->elements
;
403 if (list
->base
.dispose_fn
!= NULL
)
404 list
->base
.dispose_fn (elements
[position
]);
405 for (i
= position
+ 1; i
< count
; i
++)
406 elements
[i
- 1] = elements
[i
];
407 list
->count
= count
- 1;
412 gl_array_remove (gl_list_t list
, const void *elt
)
414 size_t position
= gl_array_indexof_from_to (list
, 0, list
->count
, elt
);
415 if (position
== (size_t)(-1))
418 return gl_array_remove_at (list
, position
);
422 gl_array_list_free (gl_list_t list
)
424 if (list
->elements
!= NULL
)
426 if (list
->base
.dispose_fn
!= NULL
)
428 size_t count
= list
->count
;
432 gl_listelement_dispose_fn dispose
= list
->base
.dispose_fn
;
433 const void **elements
= list
->elements
;
436 dispose (*elements
++);
440 free (list
->elements
);
445 /* --------------------- gl_list_iterator_t Data Type --------------------- */
447 static gl_list_iterator_t
448 gl_array_iterator (gl_list_t list
)
450 gl_list_iterator_t result
;
452 result
.vtable
= list
->base
.vtable
;
454 result
.count
= list
->count
;
455 result
.p
= list
->elements
+ 0;
456 result
.q
= list
->elements
+ list
->count
;
457 #if defined GCC_LINT || defined lint
465 static gl_list_iterator_t
466 gl_array_iterator_from_to (gl_list_t list
, size_t start_index
, size_t end_index
)
468 gl_list_iterator_t result
;
470 if (!(start_index
<= end_index
&& end_index
<= list
->count
))
471 /* Invalid arguments. */
473 result
.vtable
= list
->base
.vtable
;
475 result
.count
= list
->count
;
476 result
.p
= list
->elements
+ start_index
;
477 result
.q
= list
->elements
+ end_index
;
478 #if defined GCC_LINT || defined lint
487 gl_array_iterator_next (gl_list_iterator_t
*iterator
,
488 const void **eltp
, gl_list_node_t
*nodep
)
490 gl_list_t list
= iterator
->list
;
491 if (iterator
->count
!= list
->count
)
493 if (iterator
->count
!= list
->count
+ 1)
494 /* Concurrent modifications were done on the list. */
496 /* The last returned element was removed. */
498 iterator
->p
= (const void **) iterator
->p
- 1;
499 iterator
->q
= (const void **) iterator
->q
- 1;
501 if (iterator
->p
< iterator
->q
)
503 const void **p
= (const void **) iterator
->p
;
506 *nodep
= INDEX_TO_NODE (p
- list
->elements
);
515 gl_array_iterator_free (gl_list_iterator_t
*iterator
)
519 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
522 gl_array_sortedlist_indexof_from_to (gl_list_t list
,
523 gl_listelement_compar_fn compar
,
524 size_t low
, size_t high
,
527 if (!(low
<= high
&& high
<= list
->count
))
528 /* Invalid arguments. */
532 /* At each loop iteration, low < high; for indices < low the values
533 are smaller than ELT; for indices >= high the values are greater
534 than ELT. So, if the element occurs in the list, it is at
535 low <= position < high. */
538 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
539 int cmp
= compar (list
->elements
[mid
], elt
);
547 /* We have an element equal to ELT at index MID. But we need
548 the minimal such index. */
550 /* At each loop iteration, low <= high and
551 compar (list->elements[high], elt) == 0,
552 and we know that the first occurrence of the element is at
553 low <= position <= high. */
556 size_t mid2
= low
+ (high
- low
) / 2; /* low <= mid2 < high */
557 int cmp2
= compar (list
->elements
[mid2
], elt
);
562 /* The list was not sorted. */
575 /* Here low == high. */
581 gl_array_sortedlist_indexof (gl_list_t list
, gl_listelement_compar_fn compar
,
584 return gl_array_sortedlist_indexof_from_to (list
, compar
, 0, list
->count
,
588 static gl_list_node_t
589 gl_array_sortedlist_search_from_to (gl_list_t list
,
590 gl_listelement_compar_fn compar
,
591 size_t low
, size_t high
,
595 gl_array_sortedlist_indexof_from_to (list
, compar
, low
, high
, elt
);
596 return INDEX_TO_NODE (index
);
599 static gl_list_node_t
600 gl_array_sortedlist_search (gl_list_t list
, gl_listelement_compar_fn compar
,
604 gl_array_sortedlist_indexof_from_to (list
, compar
, 0, list
->count
, elt
);
605 return INDEX_TO_NODE (index
);
608 static gl_list_node_t
609 gl_array_sortedlist_nx_add (gl_list_t list
, gl_listelement_compar_fn compar
,
612 size_t count
= list
->count
;
616 /* At each loop iteration, low <= high; for indices < low the values are
617 smaller than ELT; for indices >= high the values are greater than ELT. */
620 size_t mid
= low
+ (high
- low
) / 2; /* low <= mid < high */
621 int cmp
= compar (list
->elements
[mid
], elt
);
633 return gl_array_nx_add_at (list
, low
, elt
);
637 gl_array_sortedlist_remove (gl_list_t list
, gl_listelement_compar_fn compar
,
640 size_t index
= gl_array_sortedlist_indexof (list
, compar
, elt
);
641 if (index
== (size_t)(-1))
644 return gl_array_remove_at (list
, index
);
648 const struct gl_list_implementation gl_array_list_implementation
=
650 gl_array_nx_create_empty
,
654 gl_array_node_nx_set_value
,
656 gl_array_previous_node
,
659 gl_array_search_from_to
,
660 gl_array_indexof_from_to
,
661 gl_array_nx_add_first
,
662 gl_array_nx_add_last
,
663 gl_array_nx_add_before
,
664 gl_array_nx_add_after
,
666 gl_array_remove_node
,
671 gl_array_iterator_from_to
,
672 gl_array_iterator_next
,
673 gl_array_iterator_free
,
674 gl_array_sortedlist_search
,
675 gl_array_sortedlist_search_from_to
,
676 gl_array_sortedlist_indexof
,
677 gl_array_sortedlist_indexof_from_to
,
678 gl_array_sortedlist_nx_add
,
679 gl_array_sortedlist_remove