1 /* Ordered set data type implemented by a binary tree.
2    Copyright (C) 2006-2007, 2009-2021 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2006.
4 
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.
9 
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.
14 
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/>.  */
17 
18 /* Common code of gl_avltree_oset.c and gl_rbtree_oset.c.  */
19 
20 /* An item on the stack used for iterating across the elements.  */
21 typedef struct
22 {
23   gl_oset_node_t node;
24   bool rightp;
25 } iterstack_item_t;
26 
27 /* A stack used for iterating across the elements.  */
28 typedef iterstack_item_t iterstack_t[MAXHEIGHT];
29 
30 static gl_oset_t
gl_tree_nx_create_empty(gl_oset_implementation_t implementation,gl_setelement_compar_fn compar_fn,gl_setelement_dispose_fn dispose_fn)31 gl_tree_nx_create_empty (gl_oset_implementation_t implementation,
32                          gl_setelement_compar_fn compar_fn,
33                          gl_setelement_dispose_fn dispose_fn)
34 {
35   struct gl_oset_impl *set =
36     (struct gl_oset_impl *) malloc (sizeof (struct gl_oset_impl));
37 
38   if (set == NULL)
39     return NULL;
40 
41   set->base.vtable = implementation;
42   set->base.compar_fn = compar_fn;
43   set->base.dispose_fn = dispose_fn;
44   set->root = NULL;
45   set->count = 0;
46 
47   return set;
48 }
49 
50 static size_t _GL_ATTRIBUTE_PURE
gl_tree_size(gl_oset_t set)51 gl_tree_size (gl_oset_t set)
52 {
53   return set->count;
54 }
55 
56 /* Returns the next node in the tree, or NULL if there is none.  */
57 static inline gl_oset_node_t _GL_ATTRIBUTE_PURE
gl_tree_next_node(gl_oset_node_t node)58 gl_tree_next_node (gl_oset_node_t node)
59 {
60   if (node->right != NULL)
61     {
62       node = node->right;
63       while (node->left != NULL)
64         node = node->left;
65     }
66   else
67     {
68       while (node->parent != NULL && node->parent->right == node)
69         node = node->parent;
70       node = node->parent;
71     }
72   return node;
73 }
74 
75 /* Returns the previous node in the tree, or NULL if there is none.  */
76 static inline gl_oset_node_t _GL_ATTRIBUTE_PURE
gl_tree_prev_node(gl_oset_node_t node)77 gl_tree_prev_node (gl_oset_node_t node)
78 {
79   if (node->left != NULL)
80     {
81       node = node->left;
82       while (node->right != NULL)
83         node = node->right;
84     }
85   else
86     {
87       while (node->parent != NULL && node->parent->left == node)
88         node = node->parent;
89       node = node->parent;
90     }
91   return node;
92 }
93 
94 static bool
gl_tree_search(gl_oset_t set,const void * elt)95 gl_tree_search (gl_oset_t set, const void *elt)
96 {
97   gl_setelement_compar_fn compar = set->base.compar_fn;
98   gl_oset_node_t node;
99 
100   for (node = set->root; node != NULL; )
101     {
102       int cmp = (compar != NULL
103                  ? compar (node->value, elt)
104                  : (node->value > elt ? 1 :
105                     node->value < elt ? -1 : 0));
106 
107       if (cmp < 0)
108         node = node->right;
109       else if (cmp > 0)
110         node = node->left;
111       else /* cmp == 0 */
112         /* We have an element equal to ELT.  */
113         return true;
114     }
115   return false;
116 }
117 
118 static bool
gl_tree_search_atleast(gl_oset_t set,gl_setelement_threshold_fn threshold_fn,const void * threshold,const void ** eltp)119 gl_tree_search_atleast (gl_oset_t set,
120                         gl_setelement_threshold_fn threshold_fn,
121                         const void *threshold,
122                         const void **eltp)
123 {
124   gl_oset_node_t node;
125 
126   for (node = set->root; node != NULL; )
127     {
128       if (! threshold_fn (node->value, threshold))
129         node = node->right;
130       else
131         {
132           /* We have an element >= THRESHOLD.  But we need the leftmost such
133              element.  */
134           gl_oset_node_t found = node;
135           node = node->left;
136           for (; node != NULL; )
137             {
138               if (! threshold_fn (node->value, threshold))
139                 node = node->right;
140               else
141                 {
142                   found = node;
143                   node = node->left;
144                 }
145             }
146           *eltp = found->value;
147           return true;
148         }
149     }
150   return false;
151 }
152 
153 static gl_oset_node_t
gl_tree_search_node(gl_oset_t set,const void * elt)154 gl_tree_search_node (gl_oset_t set, const void *elt)
155 {
156   gl_setelement_compar_fn compar = set->base.compar_fn;
157   gl_oset_node_t node;
158 
159   for (node = set->root; node != NULL; )
160     {
161       int cmp = (compar != NULL
162                  ? compar (node->value, elt)
163                  : (node->value > elt ? 1 :
164                     node->value < elt ? -1 : 0));
165 
166       if (cmp < 0)
167         node = node->right;
168       else if (cmp > 0)
169         node = node->left;
170       else /* cmp == 0 */
171         /* We have an element equal to ELT.  */
172         return node;
173     }
174   return NULL;
175 }
176 
177 static int
gl_tree_nx_add(gl_oset_t set,const void * elt)178 gl_tree_nx_add (gl_oset_t set, const void *elt)
179 {
180   gl_setelement_compar_fn compar;
181   gl_oset_node_t node = set->root;
182 
183   if (node == NULL)
184     {
185       if (gl_tree_nx_add_first (set, elt) == NULL)
186         return -1;
187       return true;
188     }
189 
190   compar = set->base.compar_fn;
191 
192   for (;;)
193     {
194       int cmp = (compar != NULL
195                  ? compar (node->value, elt)
196                  : (node->value > elt ? 1 :
197                     node->value < elt ? -1 : 0));
198 
199       if (cmp < 0)
200         {
201           if (node->right == NULL)
202             {
203               if (gl_tree_nx_add_after (set, node, elt) == NULL)
204                 return -1;
205               return true;
206             }
207           node = node->right;
208         }
209       else if (cmp > 0)
210         {
211           if (node->left == NULL)
212             {
213               if (gl_tree_nx_add_before (set, node, elt) == NULL)
214                 return -1;
215               return true;
216             }
217           node = node->left;
218         }
219       else /* cmp == 0 */
220         return false;
221     }
222 }
223 
224 static bool
gl_tree_remove(gl_oset_t set,const void * elt)225 gl_tree_remove (gl_oset_t set, const void *elt)
226 {
227   gl_oset_node_t node = gl_tree_search_node (set, elt);
228 
229   if (node != NULL)
230     return gl_tree_remove_node (set, node);
231   else
232     return false;
233 }
234 
235 static int
gl_tree_update(gl_oset_t set,const void * elt,void (* action)(const void *,void *),void * action_data)236 gl_tree_update (gl_oset_t set, const void *elt,
237                 void (*action) (const void * /*elt*/, void * /*action_data*/),
238                 void *action_data)
239 {
240   /* Like gl_tree_remove, action (...), gl_tree_nx_add, except that we don't
241      actually remove ELT.  */
242   /* Remember the old node.  Don't free it.  */
243   gl_oset_node_t old_node = gl_tree_search_node (set, elt);
244   /* Invoke ACTION.  */
245   action (elt, action_data);
246   /* Determine where to put the node now.  */
247   if (old_node != NULL)
248     {
249       if (set->count > 1)
250         {
251           gl_setelement_compar_fn compar = set->base.compar_fn;
252 
253           gl_oset_node_t prev_node = gl_tree_prev_node (old_node);
254           gl_oset_node_t next_node = gl_tree_next_node (old_node);
255           if (!(compar != NULL
256                 ? (prev_node == NULL || compar (prev_node->value, elt) < 0)
257                   && (next_node == NULL || compar (next_node->value, elt) > 0)
258                 : (prev_node == NULL || prev_node->value < elt)
259                   && (next_node == NULL || next_node->value > elt)))
260             {
261               /* old_node needs to move in the tree.  */
262               gl_oset_node_t node;
263 
264               /* Remove the node from the tree.  Don't free it.  */
265               gl_tree_remove_node_no_free (set, old_node);
266 
267               node = set->root;
268 
269               for (;;)
270                 {
271                   int cmp = (compar != NULL
272                              ? compar (node->value, elt)
273                              : (node->value > elt ? 1 :
274                                 node->value < elt ? -1 : 0));
275 
276                   if (cmp < 0)
277                     {
278                       if (node->right == NULL)
279                         {
280                           gl_tree_add_node_after (set, node, old_node);
281                           return true;
282                         }
283                       node = node->right;
284                     }
285                   else if (cmp > 0)
286                     {
287                       if (node->left == NULL)
288                         {
289                           gl_tree_add_node_before (set, node, old_node);
290                           return true;
291                         }
292                       node = node->left;
293                     }
294                   else /* cmp == 0 */
295                     {
296                       /* Two elements are the same.  */
297                       NODE_PAYLOAD_DISPOSE (set, old_node)
298                       free (old_node);
299                       return -1;
300                     }
301                 }
302             }
303         }
304     }
305   return 0;
306 }
307 
308 static void
gl_tree_oset_free(gl_oset_t set)309 gl_tree_oset_free (gl_oset_t set)
310 {
311   /* Iterate across all elements in post-order.  */
312   gl_oset_node_t node = set->root;
313   iterstack_t stack;
314   iterstack_item_t *stack_ptr = &stack[0];
315 
316   for (;;)
317     {
318       /* Descend on left branch.  */
319       for (;;)
320         {
321           if (node == NULL)
322             break;
323           stack_ptr->node = node;
324           stack_ptr->rightp = false;
325           node = node->left;
326           stack_ptr++;
327         }
328       /* Climb up again.  */
329       for (;;)
330         {
331           if (stack_ptr == &stack[0])
332             goto done_iterate;
333           stack_ptr--;
334           node = stack_ptr->node;
335           if (!stack_ptr->rightp)
336             break;
337           /* Free the current node.  */
338           if (set->base.dispose_fn != NULL)
339             set->base.dispose_fn (node->value);
340           free (node);
341         }
342       /* Descend on right branch.  */
343       stack_ptr->rightp = true;
344       node = node->right;
345       stack_ptr++;
346     }
347  done_iterate:
348   free (set);
349 }
350 
351 /* --------------------- gl_oset_iterator_t Data Type --------------------- */
352 
353 static gl_oset_iterator_t _GL_ATTRIBUTE_PURE
gl_tree_iterator(gl_oset_t set)354 gl_tree_iterator (gl_oset_t set)
355 {
356   gl_oset_iterator_t result;
357   gl_oset_node_t node;
358 
359   result.vtable = set->base.vtable;
360   result.set = set;
361   /* Start node is the leftmost node.  */
362   node = set->root;
363   if (node != NULL)
364     while (node->left != NULL)
365       node = node->left;
366   result.p = node;
367   /* End point is past the rightmost node.  */
368   result.q = NULL;
369 #if defined GCC_LINT || defined lint
370   result.i = 0;
371   result.j = 0;
372   result.count = 0;
373 #endif
374 
375   return result;
376 }
377 
378 static gl_oset_iterator_t
gl_tree_iterator_atleast(gl_oset_t set,gl_setelement_threshold_fn threshold_fn,const void * threshold)379 gl_tree_iterator_atleast (gl_oset_t set,
380                           gl_setelement_threshold_fn threshold_fn,
381                           const void *threshold)
382 {
383   gl_oset_iterator_t result;
384   gl_oset_node_t node;
385 
386   result.vtable = set->base.vtable;
387   result.set = set;
388   /* End point is past the rightmost node.  */
389   result.q = NULL;
390 #if defined GCC_LINT || defined lint
391   result.i = 0;
392   result.j = 0;
393   result.count = 0;
394 #endif
395 
396   for (node = set->root; node != NULL; )
397     {
398       if (! threshold_fn (node->value, threshold))
399         node = node->right;
400       else
401         {
402           /* We have an element >= THRESHOLD.  But we need the leftmost such
403              element.  */
404           gl_oset_node_t found = node;
405           node = node->left;
406           for (; node != NULL; )
407             {
408               if (! threshold_fn (node->value, threshold))
409                 node = node->right;
410               else
411                 {
412                   found = node;
413                   node = node->left;
414                 }
415             }
416           result.p = found;
417           return result;
418         }
419     }
420   result.p = NULL;
421   return result;
422 }
423 
424 static bool
gl_tree_iterator_next(gl_oset_iterator_t * iterator,const void ** eltp)425 gl_tree_iterator_next (gl_oset_iterator_t *iterator, const void **eltp)
426 {
427   if (iterator->p != iterator->q)
428     {
429       gl_oset_node_t node = (gl_oset_node_t) iterator->p;
430       *eltp = node->value;
431       /* Advance to the next node.  */
432       node = gl_tree_next_node (node);
433       iterator->p = node;
434       return true;
435     }
436   else
437     return false;
438 }
439 
440 static void
gl_tree_iterator_free(_GL_ATTRIBUTE_MAYBE_UNUSED gl_oset_iterator_t * iterator)441 gl_tree_iterator_free (_GL_ATTRIBUTE_MAYBE_UNUSED gl_oset_iterator_t *iterator)
442 {
443 }
444