1 /* Set data type implemented by an array.
2 Copyright (C) 2006-2019 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_set.h"
25 /* Checked size_t computations. */
29 # define uintptr_t unsigned long
32 /* --------------------------- gl_set_t Data Type --------------------------- */
34 /* Concrete gl_set_impl type, valid for this file only. */
37 struct gl_set_impl_base base
;
38 /* An array of ALLOCATED elements, of which the first COUNT are used.
39 0 <= COUNT <= ALLOCATED. */
40 const void **elements
;
46 gl_array_nx_create_empty (gl_set_implementation_t implementation
,
47 gl_setelement_equals_fn equals_fn
,
48 gl_setelement_hashcode_fn hashcode_fn
,
49 gl_setelement_dispose_fn dispose_fn
)
51 struct gl_set_impl
*set
=
52 (struct gl_set_impl
*) malloc (sizeof (struct gl_set_impl
));
57 set
->base
.vtable
= implementation
;
58 set
->base
.equals_fn
= equals_fn
;
59 set
->base
.dispose_fn
= dispose_fn
;
68 gl_array_size (gl_set_t set
)
74 gl_array_search (gl_set_t set
, const void *elt
)
76 size_t count
= set
->count
;
80 gl_setelement_equals_fn equals
= set
->base
.equals_fn
;
81 const void **elements
= set
->elements
;
86 for (i
= 0; i
< count
; i
++)
87 if (equals (elements
[i
], elt
))
94 for (i
= 0; i
< count
; i
++)
95 if (elements
[i
] == elt
)
102 /* Ensure that set->allocated > set->count.
103 Return 0 upon success, -1 upon out-of-memory. */
107 size_t new_allocated
;
111 new_allocated
= xtimes (set
->allocated
, 2);
112 new_allocated
= xsum (new_allocated
, 1);
113 memory_size
= xtimes (new_allocated
, sizeof (const void *));
114 if (size_overflow_p (memory_size
))
115 /* Overflow, would lead to out of memory. */
117 memory
= (const void **) realloc (set
->elements
, memory_size
);
121 set
->elements
= memory
;
122 set
->allocated
= new_allocated
;
127 gl_array_nx_add (gl_set_t set
, const void *elt
)
129 if (gl_array_search (set
, elt
))
133 size_t count
= set
->count
;
135 if (count
== set
->allocated
)
138 set
->elements
[count
] = elt
;
139 set
->count
= count
+ 1;
144 /* Remove the element at the given position,
145 0 <= position < gl_set_size (set). */
147 gl_array_remove_at (gl_set_t set
, size_t position
)
149 size_t count
= set
->count
;
150 const void **elements
= set
->elements
;
153 if (set
->base
.dispose_fn
!= NULL
)
154 set
->base
.dispose_fn (elements
[position
]);
155 for (i
= position
+ 1; i
< count
; i
++)
156 elements
[i
- 1] = elements
[i
];
157 set
->count
= count
- 1;
161 gl_array_remove (gl_set_t set
, const void *elt
)
163 size_t count
= set
->count
;
167 gl_setelement_equals_fn equals
= set
->base
.equals_fn
;
168 const void **elements
= set
->elements
;
174 for (i
= 0; i
< count
; i
++)
175 if (equals (elements
[i
], elt
))
177 gl_array_remove_at (set
, i
);
185 for (i
= 0; i
< count
; i
++)
186 if (elements
[i
] == elt
)
188 gl_array_remove_at (set
, i
);
197 gl_array_free (gl_set_t set
)
199 if (set
->elements
!= NULL
)
201 if (set
->base
.dispose_fn
!= NULL
)
203 size_t count
= set
->count
;
207 gl_setelement_dispose_fn dispose
= set
->base
.dispose_fn
;
208 const void **elements
= set
->elements
;
211 dispose (*elements
++);
215 free (set
->elements
);
220 /* ---------------------- gl_set_iterator_t Data Type ---------------------- */
222 static gl_set_iterator_t
223 gl_array_iterator (gl_set_t set
)
225 gl_set_iterator_t result
;
227 result
.vtable
= set
->base
.vtable
;
229 result
.count
= set
->count
;
230 result
.p
= set
->elements
+ 0;
231 result
.q
= set
->elements
+ set
->count
;
232 #if defined GCC_LINT || defined lint
241 gl_array_iterator_next (gl_set_iterator_t
*iterator
, const void **eltp
)
243 gl_set_t set
= iterator
->set
;
244 if (iterator
->count
!= set
->count
)
246 if (iterator
->count
!= set
->count
+ 1)
247 /* Concurrent modifications were done on the set. */
249 /* The last returned element was removed. */
251 iterator
->p
= (const void **) iterator
->p
- 1;
252 iterator
->q
= (const void **) iterator
->q
- 1;
254 if (iterator
->p
< iterator
->q
)
256 const void **p
= (const void **) iterator
->p
;
266 gl_array_iterator_free (gl_set_iterator_t
*iterator
)
271 const struct gl_set_implementation gl_array_set_implementation
=
273 gl_array_nx_create_empty
,
280 gl_array_iterator_next
,
281 gl_array_iterator_free