1 /* Sequential list data type backed by another list.
2 Copyright (C) 2006-2024 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_sublist.h"
26 /* -------------------------- gl_list_t Data Type -------------------------- */
28 /* Concrete gl_list_impl type, valid for this file only. */
31 struct gl_list_impl_base base
;
32 /* Reference to the whole list. */
34 /* Limits of the index range. */
39 /* struct gl_list_node_impl doesn't exist here. The pointers are actually
40 indices + 1. (We don't use the whole list's gl_list_node_t implementation,
41 because gl_sublist_next_node and gl_sublist_previous_node would not be easy
42 to implement with this choice.) */
43 #define INDEX_TO_NODE(index) (gl_list_node_t)(uintptr_t)(size_t)((index) + 1)
44 #define NODE_TO_INDEX(node) ((uintptr_t)(node) - 1)
47 gl_sublist_nx_create_empty (gl_list_implementation_t implementation
,
48 gl_listelement_equals_fn equals_fn
,
49 gl_listelement_hashcode_fn hashcode_fn
,
50 gl_listelement_dispose_fn dispose_fn
,
51 bool allow_duplicates
)
53 /* Shouldn't be called. */
58 gl_sublist_nx_create_fill (gl_list_implementation_t implementation
,
59 gl_listelement_equals_fn equals_fn
,
60 gl_listelement_hashcode_fn hashcode_fn
,
61 gl_listelement_dispose_fn dispose_fn
,
62 bool allow_duplicates
,
63 size_t count
, const void **contents
)
65 /* Shouldn't be called. */
70 gl_sublist_size (gl_list_t list
)
72 return list
->end
- list
->start
;
76 gl_sublist_node_value (gl_list_t list
, gl_list_node_t node
)
78 uintptr_t index
= NODE_TO_INDEX (node
);
79 if (!(index
< list
->end
- list
->start
))
80 /* Invalid argument. */
82 return gl_list_get_at (list
->whole
, list
->start
+ index
);
86 gl_sublist_node_nx_set_value (gl_list_t list
, gl_list_node_t node
, const void *elt
)
88 uintptr_t index
= NODE_TO_INDEX (node
);
89 if (!(index
< list
->end
- list
->start
))
90 /* Invalid argument. */
92 if (gl_list_nx_set_at (list
->whole
, list
->start
+ index
, elt
) == NULL
)
98 gl_sublist_next_node (gl_list_t list
, gl_list_node_t node
)
100 uintptr_t index
= NODE_TO_INDEX (node
);
101 size_t count
= list
->end
- list
->start
;
102 if (!(index
< count
))
103 /* Invalid argument. */
107 return INDEX_TO_NODE (index
);
112 static gl_list_node_t
113 gl_sublist_previous_node (gl_list_t list
, gl_list_node_t node
)
115 uintptr_t index
= NODE_TO_INDEX (node
);
116 if (!(index
< list
->end
- list
->start
))
117 /* Invalid argument. */
120 return INDEX_TO_NODE (index
- 1);
125 static gl_list_node_t
126 gl_sublist_first_node (gl_list_t list
)
128 if (list
->end
> list
->start
)
129 return INDEX_TO_NODE (0);
134 static gl_list_node_t
135 gl_sublist_last_node (gl_list_t list
)
137 size_t count
= list
->end
- list
->start
;
139 return INDEX_TO_NODE (count
- 1);
145 gl_sublist_get_at (gl_list_t list
, size_t position
)
147 if (!(position
< list
->end
- list
->start
))
148 /* Invalid argument. */
150 return gl_list_get_at (list
->whole
, list
->start
+ position
);
153 static gl_list_node_t
154 gl_sublist_nx_set_at (gl_list_t list
, size_t position
, const void *elt
)
156 if (!(position
< list
->end
- list
->start
))
157 /* Invalid argument. */
159 if (gl_list_nx_set_at (list
->whole
, list
->start
+ position
, elt
) == NULL
)
161 return INDEX_TO_NODE (position
);
164 static gl_list_node_t
165 gl_sublist_search_from_to (gl_list_t list
, size_t start_index
, size_t end_index
,
168 if (!(start_index
<= end_index
&& end_index
<= list
->end
- list
->start
))
169 /* Invalid arguments. */
173 gl_list_indexof_from_to (list
->whole
,
174 list
->start
+ start_index
,
175 list
->start
+ end_index
,
177 if (index
!= (size_t)(-1))
178 return INDEX_TO_NODE (index
- list
->start
);
185 gl_sublist_indexof_from_to (gl_list_t list
,
186 size_t start_index
, size_t end_index
,
189 if (!(start_index
<= end_index
&& end_index
<= list
->end
- list
->start
))
190 /* Invalid arguments. */
194 gl_list_indexof_from_to (list
->whole
,
195 list
->start
+ start_index
,
196 list
->start
+ end_index
,
198 if (index
!= (size_t)(-1))
199 index
-= list
->start
;
204 static gl_list_node_t
205 gl_sublist_nx_add_first (gl_list_t list
, const void *elt
)
207 if (gl_list_nx_add_at (list
->whole
, list
->start
, elt
) == NULL
)
210 return INDEX_TO_NODE (0);
213 static gl_list_node_t
214 gl_sublist_nx_add_last (gl_list_t list
, const void *elt
)
216 if (gl_list_nx_add_at (list
->whole
, list
->end
, elt
) == NULL
)
219 return INDEX_TO_NODE (list
->end
- list
->start
- 1);
222 static gl_list_node_t
223 gl_sublist_nx_add_before (gl_list_t list
, gl_list_node_t node
, const void *elt
)
225 size_t position
= NODE_TO_INDEX (node
);
226 if (!(position
< list
->end
- list
->start
))
227 /* Invalid argument. */
229 if (gl_list_nx_add_at (list
->whole
, list
->start
+ position
, elt
) == NULL
)
232 return INDEX_TO_NODE (position
);
235 static gl_list_node_t
236 gl_sublist_nx_add_after (gl_list_t list
, gl_list_node_t node
, const void *elt
)
238 size_t position
= NODE_TO_INDEX (node
);
239 if (!(position
< list
->end
- list
->start
))
240 /* Invalid argument. */
243 if (gl_list_nx_add_at (list
->whole
, list
->start
+ position
, elt
) == NULL
)
246 return INDEX_TO_NODE (position
);
249 static gl_list_node_t
250 gl_sublist_nx_add_at (gl_list_t list
, size_t position
, const void *elt
)
252 if (!(position
<= list
->end
- list
->start
))
253 /* Invalid argument. */
255 if (gl_list_nx_add_at (list
->whole
, list
->start
+ position
, elt
) == NULL
)
258 return INDEX_TO_NODE (position
);
262 gl_sublist_remove_node (gl_list_t list
, gl_list_node_t node
)
264 uintptr_t index
= NODE_TO_INDEX (node
);
265 if (!(index
< list
->end
- list
->start
))
266 /* Invalid argument. */
268 return gl_list_remove_at (list
->whole
, list
->start
+ index
);
272 gl_sublist_remove_at (gl_list_t list
, size_t position
)
274 if (!(position
< list
->end
- list
->start
))
275 /* Invalid argument. */
277 return gl_list_remove_at (list
->whole
, list
->start
+ position
);
281 gl_sublist_remove (gl_list_t list
, const void *elt
)
284 gl_list_indexof_from_to (list
->whole
, list
->start
, list
->end
, elt
);
285 if (position
== (size_t)(-1))
288 return gl_list_remove_at (list
->whole
, position
);
292 gl_sublist_list_free (gl_list_t list
)
297 /* --------------------- gl_list_iterator_t Data Type --------------------- */
299 static gl_list_iterator_t
300 gl_sublist_iterator (gl_list_t list
)
302 return gl_list_iterator_from_to (list
->whole
, list
->start
, list
->end
);
305 static gl_list_iterator_t
306 gl_sublist_iterator_from_to (gl_list_t list
,
307 size_t start_index
, size_t end_index
)
309 if (!(start_index
<= end_index
&& end_index
<= list
->end
- list
->start
))
310 /* Invalid arguments. */
312 return gl_list_iterator_from_to (list
->whole
,
313 list
->start
+ start_index
,
314 list
->start
+ end_index
);
318 gl_sublist_iterator_next (gl_list_iterator_t
*iterator
,
319 const void **eltp
, gl_list_node_t
*nodep
)
321 /* Shouldn't be called. */
326 gl_sublist_iterator_free (gl_list_iterator_t
*iterator
)
328 /* Shouldn't be called. */
332 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
334 static gl_list_node_t
335 gl_sublist_sortedlist_search (gl_list_t list
,
336 gl_listelement_compar_fn compar
,
340 gl_sortedlist_indexof_from_to (list
->whole
, compar
,
341 list
->start
, list
->end
, elt
);
342 if (index
!= (size_t)(-1))
343 return INDEX_TO_NODE (index
- list
->start
);
348 static gl_list_node_t
349 gl_sublist_sortedlist_search_from_to (gl_list_t list
,
350 gl_listelement_compar_fn compar
,
351 size_t low
, size_t high
,
356 if (!(low
<= high
&& high
<= list
->end
- list
->start
))
357 /* Invalid arguments. */
361 gl_sortedlist_indexof_from_to (list
->whole
, compar
,
362 list
->start
+ low
, list
->start
+ high
, elt
);
363 if (index
!= (size_t)(-1))
364 return INDEX_TO_NODE (index
- list
->start
);
370 gl_sublist_sortedlist_indexof (gl_list_t list
,
371 gl_listelement_compar_fn compar
,
375 gl_sortedlist_indexof_from_to (list
->whole
, compar
, list
->start
, list
->end
,
377 if (index
!= (size_t)(-1))
378 index
-= list
->start
;
383 gl_sublist_sortedlist_indexof_from_to (gl_list_t list
,
384 gl_listelement_compar_fn compar
,
385 size_t low
, size_t high
,
390 if (!(low
<= high
&& high
<= list
->end
- list
->start
))
391 /* Invalid arguments. */
394 index
= gl_sortedlist_indexof_from_to (list
->whole
, compar
,
395 list
->start
+ low
, list
->start
+ high
,
397 if (index
!= (size_t)(-1))
398 index
-= list
->start
;
402 static gl_list_node_t
403 gl_sublist_sortedlist_nx_add (gl_list_t list
,
404 gl_listelement_compar_fn compar
,
407 /* It's impossible to implement this method without risking to put the
408 whole list into unsorted order (namely, when the given ELT is smaller
409 or larger than all elements of the sublist). */
414 gl_sublist_sortedlist_remove (gl_list_t list
,
415 gl_listelement_compar_fn compar
,
418 size_t index
= gl_sublist_sortedlist_indexof (list
, compar
, elt
);
419 if (index
== (size_t)(-1))
422 return gl_sublist_remove_at (list
, index
);
426 static const struct gl_list_implementation gl_sublist_list_implementation
=
428 gl_sublist_nx_create_empty
,
429 gl_sublist_nx_create_fill
,
431 gl_sublist_node_value
,
432 gl_sublist_node_nx_set_value
,
433 gl_sublist_next_node
,
434 gl_sublist_previous_node
,
435 gl_sublist_first_node
,
436 gl_sublist_last_node
,
438 gl_sublist_nx_set_at
,
439 gl_sublist_search_from_to
,
440 gl_sublist_indexof_from_to
,
441 gl_sublist_nx_add_first
,
442 gl_sublist_nx_add_last
,
443 gl_sublist_nx_add_before
,
444 gl_sublist_nx_add_after
,
445 gl_sublist_nx_add_at
,
446 gl_sublist_remove_node
,
447 gl_sublist_remove_at
,
449 gl_sublist_list_free
,
451 gl_sublist_iterator_from_to
,
452 gl_sublist_iterator_next
,
453 gl_sublist_iterator_free
,
454 gl_sublist_sortedlist_search
,
455 gl_sublist_sortedlist_search_from_to
,
456 gl_sublist_sortedlist_indexof
,
457 gl_sublist_sortedlist_indexof_from_to
,
458 gl_sublist_sortedlist_nx_add
,
459 gl_sublist_sortedlist_remove
463 gl_sublist_nx_create (gl_list_t whole_list
, size_t start_index
, size_t end_index
)
465 if (!(start_index
<= end_index
&& end_index
<= gl_list_size (whole_list
)))
466 /* Invalid arguments. */
469 struct gl_list_impl
*list
=
470 (struct gl_list_impl
*) malloc (sizeof (struct gl_list_impl
));
475 list
->base
.vtable
= &gl_sublist_list_implementation
;
476 list
->base
.equals_fn
= whole_list
->base
.equals_fn
; /* actually unused */
477 list
->base
.hashcode_fn
= whole_list
->base
.hashcode_fn
; /* actually unused */
478 list
->base
.dispose_fn
= whole_list
->base
.dispose_fn
; /* actually unused */
479 list
->base
.allow_duplicates
= whole_list
->base
.allow_duplicates
; /* unused */
480 if (whole_list
->base
.vtable
== &gl_sublist_list_implementation
)
482 /* Optimization of a sublist of a sublist: Collapse the two
483 indirections into a single indirection. */
484 list
->whole
= whole_list
->whole
;
485 list
->start
= whole_list
->start
+ start_index
;
486 list
->end
= whole_list
->start
+ end_index
;
490 list
->whole
= whole_list
;
491 list
->start
= start_index
;
492 list
->end
= end_index
;