1 /* -*- mode: C -*-
2 *
3 * File: rec-mset.c
4 * Date: Thu Apr 1 17:07:00 2010
5 *
6 * GNU recutils - Ordered Heterogeneous Set
7 *
8 */
9
10 /* Copyright (C) 2010-2019 Jose E. Marchesi */
11
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include <config.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include <rec.h>
33
34 #include <gl_array_list.h>
35 #include <gl_list.h>
36
37 /*
38 * Data types.
39 */
40
41 #define MAX_NTYPES 4
42
43 struct rec_mset_elem_s
44 {
45 rec_mset_type_t type;
46 void *data;
47
48 gl_list_node_t list_node;
49
50 /* Containing multi-set. */
51 rec_mset_t mset;
52 };
53
54 struct rec_mset_s
55 {
56 int ntypes;
57
58 /* Properties of the element types. */
59 char *name[MAX_NTYPES];
60 rec_mset_disp_fn_t disp_fn[MAX_NTYPES];
61 rec_mset_equal_fn_t equal_fn[MAX_NTYPES];
62 rec_mset_dup_fn_t dup_fn[MAX_NTYPES];
63 rec_mset_compare_fn_t compare_fn[MAX_NTYPES];
64
65 /* Statistics. */
66 size_t count[MAX_NTYPES];
67
68 gl_list_t elem_list;
69 };
70
71 /*
72 * Forward declarations of static functions.
73 */
74
75 static void rec_mset_init (rec_mset_t mset);
76
77 static bool rec_mset_elem_equal_fn (const void *e1,
78 const void *e2);
79 static void rec_mset_elem_dispose_fn (const void *e);
80 static int rec_mset_elem_compare_fn (const void *e1, const void *e2);
81
82 static rec_mset_list_iter_t rec_mset_iter_gl2mset (gl_list_iterator_t list_iter);
83 static gl_list_iterator_t rec_mset_iter_mset2gl (rec_mset_list_iter_t mset_iter);
84
85 /* Create a new element to be stored in a given mset, of the givent
86 type, and return it. NULL is returned if there is no enough memory
87 to perform the operation. */
88
89 static rec_mset_elem_t rec_mset_elem_new (rec_mset_t mset,
90 rec_mset_type_t type,
91 void *data);
92
93 /* Destroy the resources used by a mset element, freeing any used
94 memory. The element reference becomes invalid after executing this
95 function. */
96
97 static void rec_mset_elem_destroy (rec_mset_elem_t elem);
98
99 /*
100 * Public functions.
101 */
102
103 rec_mset_t
rec_mset_new(void)104 rec_mset_new (void)
105 {
106 rec_mset_t new;
107 int i;
108
109 new = malloc (sizeof (struct rec_mset_s));
110 if (new)
111 {
112 rec_mset_init (new);
113
114 new->ntypes = 1;
115
116 for (i = 0; i < MAX_NTYPES; i++)
117 {
118 new->count[i] = 0;
119 new->name[i] = NULL;
120 new->equal_fn[i] = NULL;
121 new->disp_fn[i] = NULL;
122 new->dup_fn[i] = NULL;
123 new->compare_fn[i] = NULL;
124 }
125
126 new->elem_list = gl_list_nx_create_empty (GL_ARRAY_LIST,
127 rec_mset_elem_equal_fn,
128 NULL,
129 rec_mset_elem_dispose_fn,
130 true);
131
132 if (new->elem_list == NULL)
133 {
134 /* Out of memory. */
135 rec_mset_destroy (new);
136 new = NULL;
137 }
138 }
139
140 return new;
141 }
142
143 void
rec_mset_destroy(rec_mset_t mset)144 rec_mset_destroy (rec_mset_t mset)
145 {
146 if (mset)
147 {
148 int i;
149
150 for (i = 0; i < mset->ntypes; i++)
151 free(mset->name[i]);
152 gl_list_free (mset->elem_list);
153 free (mset);
154 }
155 }
156
157 rec_mset_t
rec_mset_dup(rec_mset_t mset)158 rec_mset_dup (rec_mset_t mset)
159 {
160 rec_mset_t new;
161 rec_mset_elem_t elem;
162 gl_list_iterator_t iter;
163 int i;
164
165 new = rec_mset_new ();
166
167 if (new)
168 {
169 /* Register the types. */
170 new->ntypes = mset->ntypes;
171 for (i = 0; i < new->ntypes; i++)
172 {
173 new->count[i] = 0;
174 if (mset->name[i])
175 {
176 new->name[i] = strdup (mset->name[i]);
177 if (!new->name[i])
178 {
179 /* Out of memory. */
180 rec_mset_destroy (new);
181 return NULL;
182 }
183 }
184 new->disp_fn[i] = mset->disp_fn[i];
185 new->equal_fn[i] = mset->equal_fn[i];
186 new->dup_fn[i] = mset->dup_fn[i];
187 new->compare_fn[i] = mset->compare_fn[i];
188 }
189
190 /* Duplicate the elements. */
191
192 iter = gl_list_iterator (mset->elem_list);
193 while (gl_list_iterator_next (&iter, (const void **) &elem, NULL))
194 {
195 void *data = NULL;
196
197 /* Set the data. */
198 if (new->dup_fn[elem->type])
199 {
200 data = (new->dup_fn[elem->type]) (elem->data);
201 if (!data)
202 {
203 /* Out of memory. */
204 rec_mset_destroy (new);
205 return NULL;
206 }
207 }
208 else
209 {
210 data = elem->data;
211 }
212
213 /* Append the new data into a new element. */
214
215 rec_mset_append (new, elem->type, data, MSET_ANY);
216 }
217
218 gl_list_iterator_free (&iter);
219 }
220
221 return new;
222 }
223
224 rec_mset_t
rec_mset_sort(rec_mset_t mset)225 rec_mset_sort (rec_mset_t mset)
226 {
227 rec_mset_elem_t elem;
228 gl_list_iterator_t iter;
229 gl_list_t list;
230
231 /* Save a reference to the old gnulib list and create a new, empty
232 one. */
233
234 list = mset->elem_list;
235 mset->elem_list = gl_list_nx_create_empty (GL_ARRAY_LIST,
236 rec_mset_elem_equal_fn,
237 NULL,
238 rec_mset_elem_dispose_fn,
239 true);
240 if (!mset->elem_list)
241 {
242 /* Out of memory. */
243 return NULL;
244 }
245
246 /* Iterate on the old list getting the data of the elements and
247 inserting it into the new sorted gl_list. */
248
249 iter = gl_list_iterator (list);
250 while (gl_list_iterator_next (&iter, (const void **) &elem, NULL))
251 {
252 /* Create a new node list with the proper data and insert it
253 into the list using whatever sorting criteria is implemented
254 by compare_fn. */
255
256 if (!rec_mset_add_sorted (mset, elem->type, elem->data))
257 {
258 /* Out of memory. Delete the new list and restore the old
259 one. */
260
261 gl_list_free (mset->elem_list);
262 mset->elem_list = list;
263 return NULL;
264 }
265
266 /* We don't want the memory used by the element to be disposed
267 when the old list gets destroyed. The generic element
268 disposal function always checks if the data is NULL before
269 invoking the corresponding disp_fn callback. */
270
271 elem->data = NULL;
272 }
273 gl_list_iterator_free (&iter);
274
275 /* Destroy the memory used by the old list, but removing the
276 dispose_fn callbacks first for the proper types in order to avoid
277 the disposal of the elements!. */
278
279 gl_list_free (list);
280
281 return mset;
282 }
283
284 bool
rec_mset_type_p(rec_mset_t mset,rec_mset_type_t type)285 rec_mset_type_p (rec_mset_t mset,
286 rec_mset_type_t type)
287 {
288 return type < mset->ntypes;
289 }
290
291 rec_mset_type_t
rec_mset_register_type(rec_mset_t mset,char * name,rec_mset_disp_fn_t disp_fn,rec_mset_equal_fn_t equal_fn,rec_mset_dup_fn_t dup_fn,rec_mset_compare_fn_t compare_fn)292 rec_mset_register_type (rec_mset_t mset,
293 char *name,
294 rec_mset_disp_fn_t disp_fn,
295 rec_mset_equal_fn_t equal_fn,
296 rec_mset_dup_fn_t dup_fn,
297 rec_mset_compare_fn_t compare_fn)
298 {
299 rec_mset_type_t new_type;
300
301 new_type = mset->ntypes++;
302 mset->count[new_type] = 0;
303 mset->name[new_type] = strdup (name);
304 mset->disp_fn[new_type] = disp_fn;
305 mset->equal_fn[new_type] = equal_fn;
306 mset->dup_fn[new_type] = dup_fn;
307 mset->compare_fn[new_type] = compare_fn;
308
309 return new_type;
310 }
311
312 size_t
rec_mset_count(rec_mset_t mset,rec_mset_type_t type)313 rec_mset_count (rec_mset_t mset,
314 rec_mset_type_t type)
315 {
316 return mset->count[type];
317 }
318
319 void *
rec_mset_get_at(rec_mset_t mset,rec_mset_type_t type,size_t position)320 rec_mset_get_at (rec_mset_t mset,
321 rec_mset_type_t type,
322 size_t position)
323 {
324 void *result;
325 rec_mset_elem_t elem;
326
327 if ((position < 0) || (position >= mset->count[type]))
328 {
329 /* Invalid position. */
330 return NULL;
331 }
332
333 if (type == MSET_ANY)
334 {
335 /* An element of any type was requested. Simply call the gnulib
336 list get_at function, that will use the most efficient way to
337 retrieve the element. */
338
339 elem = (rec_mset_elem_t) gl_list_get_at (mset->elem_list,
340 position);
341
342 }
343 else
344 {
345 /* Iterate on the elements in the gnulib list until the
346 POSITIONth element of the specified type is found. */
347
348 rec_mset_elem_t cur_elem;
349 gl_list_node_t node;
350 gl_list_iterator_t iter;
351 int count[MAX_NTYPES];
352 int i = 0;
353
354 elem = NULL;
355 for (i = 0; i < MAX_NTYPES; i++)
356 {
357 count[i] = 0;
358 }
359
360 iter = gl_list_iterator (mset->elem_list);
361 while (gl_list_iterator_next (&iter, (const void **) &cur_elem, &node))
362 {
363 if ((type == MSET_ANY)
364 || ((type == cur_elem->type) && (count[cur_elem->type] == position)))
365 {
366 elem = cur_elem;
367 break;
368 }
369 else
370 {
371 count[cur_elem->type]++;
372 count[0]++;
373 }
374 }
375 }
376
377 if (elem)
378 {
379 result = elem->data;
380 }
381 else
382 {
383 result = NULL;
384 }
385
386 return result;
387 }
388
389 bool
rec_mset_remove_at(rec_mset_t mset,rec_mset_type_t type,size_t position)390 rec_mset_remove_at (rec_mset_t mset,
391 rec_mset_type_t type,
392 size_t position)
393 {
394 rec_mset_elem_t elem;
395 void *data;
396 bool removed = false;
397
398 if (mset->count[type] > 0)
399 {
400 if (position < 0)
401 {
402 position = 0;
403 }
404 if (position >= mset->count[type])
405 {
406 position = mset->count[type] - 1;
407 }
408
409 data = rec_mset_get_at (mset, type, position);
410 elem = rec_mset_search (mset, data);
411 if (rec_mset_remove_elem (mset, elem))
412 {
413 removed = true;
414 }
415 }
416
417 return removed;
418 }
419
420 rec_mset_elem_t
rec_mset_insert_at(rec_mset_t mset,rec_mset_type_t type,void * data,size_t position)421 rec_mset_insert_at (rec_mset_t mset,
422 rec_mset_type_t type,
423 void *data,
424 size_t position)
425 {
426 rec_mset_elem_t elem = NULL;
427 gl_list_node_t node;
428
429 node = NULL;
430
431 /* Create the mset element to insert in the gl_list, returning NULL
432 if there is no enough memory. */
433
434 elem = rec_mset_elem_new (mset, type, data);
435 if (!elem)
436 {
437 return NULL;
438 }
439
440 /* Insert the element at the proper place in the list. */
441
442 if (position < 0)
443 {
444 node = gl_list_nx_add_first (mset->elem_list,
445 (void *) elem);
446 }
447 else if (position >= mset->count[0])
448 {
449 node = gl_list_nx_add_last (mset->elem_list,
450 (void *) elem);
451 }
452 else
453 {
454 node = gl_list_nx_add_at (mset->elem_list,
455 position,
456 (void *) elem);
457 }
458
459 if (node == NULL)
460 {
461 rec_mset_elem_destroy (elem);
462 elem = NULL;
463 }
464 else
465 {
466 elem->list_node = node;
467
468 mset->count[0]++;
469 if (elem->type != MSET_ANY)
470 {
471 mset->count[elem->type]++;
472 }
473 }
474
475 return elem;
476 }
477
478 rec_mset_elem_t
rec_mset_append(rec_mset_t mset,rec_mset_type_t elem_type,void * data,rec_mset_type_t type)479 rec_mset_append (rec_mset_t mset,
480 rec_mset_type_t elem_type,
481 void *data,
482 rec_mset_type_t type)
483 {
484 return rec_mset_insert_at (mset,
485 elem_type,
486 data,
487 rec_mset_count (mset, type));
488 }
489
490 bool
rec_mset_remove_elem(rec_mset_t mset,rec_mset_elem_t elem)491 rec_mset_remove_elem (rec_mset_t mset,
492 rec_mset_elem_t elem)
493 {
494 rec_mset_type_t type = elem->type;
495 bool res = gl_list_remove_node (mset->elem_list, elem->list_node);
496 if (res)
497 {
498 /* Update statistics. */
499
500 mset->count[type]--;
501 if (type != MSET_ANY)
502 {
503 mset->count[MSET_ANY]--;
504 }
505 }
506
507 return res;
508 }
509
510 rec_mset_elem_t
rec_mset_insert_after(rec_mset_t mset,rec_mset_type_t type,void * data,rec_mset_elem_t elem)511 rec_mset_insert_after (rec_mset_t mset,
512 rec_mset_type_t type,
513 void *data,
514 rec_mset_elem_t elem)
515 {
516 rec_mset_elem_t new_elem;
517 gl_list_node_t node;
518
519 /* Create the mset element to insert in the gl_list, returning NULL
520 if there is no enough memory. */
521
522 new_elem = rec_mset_elem_new (mset, type, data);
523 if (!new_elem)
524 {
525 return NULL;
526 }
527
528 /* Find the requested place where to insert the new element. If
529 ELEM is not found in the multi-set then the new element is
530 appended to the multi-set. */
531
532 node = gl_list_search (mset->elem_list, (void *) elem);
533 if (node)
534 {
535 node = gl_list_nx_add_after (mset->elem_list,
536 node,
537 (void *) new_elem);
538 if (!node)
539 {
540 /* Out of memory. */
541 rec_mset_elem_destroy (new_elem);
542 return NULL;
543 }
544
545 new_elem->list_node = node;
546
547 mset->count[0]++;
548 if (new_elem->type != MSET_ANY)
549 {
550 mset->count[new_elem->type]++;
551 }
552 }
553 else
554 {
555 node = gl_list_nx_add_last (mset->elem_list, (void *) elem);
556 if (!node)
557 {
558 /* Out of memory. */
559 rec_mset_elem_destroy (new_elem);
560 return NULL;
561 }
562
563 new_elem->list_node = node;
564 }
565
566 return new_elem;
567 }
568
569 rec_mset_elem_t
rec_mset_search(rec_mset_t mset,void * data)570 rec_mset_search (rec_mset_t mset,
571 void *data)
572 {
573 rec_mset_elem_t result = NULL;
574 rec_mset_elem_t elem;
575 gl_list_iterator_t iter;
576
577 iter = gl_list_iterator (mset->elem_list);
578 while (gl_list_iterator_next (&iter, (const void **) &elem, NULL))
579 {
580 if (elem->data == data)
581 {
582 result = elem;
583 break;
584 }
585 }
586
587 gl_list_iterator_free (&iter);
588
589 return result;
590 }
591
592 rec_mset_iterator_t
rec_mset_iterator(rec_mset_t mset)593 rec_mset_iterator (rec_mset_t mset)
594 {
595 gl_list_iterator_t list_iter;
596 rec_mset_iterator_t mset_iter;
597
598 /* Fill the mset iterator structure. Note that the list_iter field
599 of the mset iterator must have the same size and structure than
600 the gl_list_iterator_t structure. */
601
602 mset_iter.mset = mset;
603
604 list_iter = gl_list_iterator (mset->elem_list);
605 mset_iter.list_iter = rec_mset_iter_gl2mset (list_iter);
606
607 return mset_iter;
608 }
609
610 bool
rec_mset_iterator_next(rec_mset_iterator_t * iterator,rec_mset_type_t type,const void ** data,rec_mset_elem_t * elem)611 rec_mset_iterator_next (rec_mset_iterator_t *iterator,
612 rec_mset_type_t type,
613 const void **data,
614 rec_mset_elem_t *elem)
615 {
616 bool found = true;
617 rec_mset_elem_t mset_elem;
618 gl_list_iterator_t list_iter;
619 gl_list_node_t list_node;
620
621 /* Extract the list iterator from the multi-set iterator. */
622
623 list_iter = rec_mset_iter_mset2gl (iterator->list_iter);
624
625 /* Advance the list iterator until an element of the proper type is
626 found. */
627
628 while ((found = gl_list_iterator_next (&list_iter, (const void**) &mset_elem, &list_node))
629 && (type != 0) && (mset_elem->type != type));
630
631 if (found)
632 {
633 /* Update the multi-set iterator and set both DATA and ELEM. */
634
635 iterator->list_iter = rec_mset_iter_gl2mset (list_iter);
636 if (data)
637 *data = mset_elem->data;
638 if (elem)
639 {
640 mset_elem->list_node = list_node;
641 *elem = mset_elem;
642 }
643 }
644
645 return found;
646 }
647
648 void
rec_mset_iterator_free(rec_mset_iterator_t * iterator)649 rec_mset_iterator_free (rec_mset_iterator_t *iterator)
650 {
651 gl_list_iterator_t list_iter;
652
653 /* Extract the list iterator, free it and copy it back to the mset
654 iterator. */
655
656 list_iter = rec_mset_iter_mset2gl (iterator->list_iter);
657 gl_list_iterator_free (&list_iter);
658 iterator->list_iter = rec_mset_iter_gl2mset (list_iter);
659 }
660
661 int
rec_mset_elem_type(rec_mset_elem_t elem)662 rec_mset_elem_type (rec_mset_elem_t elem)
663 {
664 return elem->type;
665 }
666
667 void
rec_mset_elem_set_type(rec_mset_elem_t elem,rec_mset_type_t type)668 rec_mset_elem_set_type (rec_mset_elem_t elem,
669 rec_mset_type_t type)
670 {
671 elem->mset->count[elem->type]--;
672 elem->type = type;
673 elem->mset->count[type]++;
674 }
675
676 void *
rec_mset_elem_data(rec_mset_elem_t elem)677 rec_mset_elem_data (rec_mset_elem_t elem)
678 {
679 return elem->data;
680 }
681
682 void
rec_mset_elem_set_data(rec_mset_elem_t elem,void * data)683 rec_mset_elem_set_data (rec_mset_elem_t elem,
684 void *data)
685 {
686 elem->data = data;
687 }
688
689 bool
rec_mset_elem_equal_p(rec_mset_elem_t elem1,rec_mset_elem_t elem2)690 rec_mset_elem_equal_p (rec_mset_elem_t elem1,
691 rec_mset_elem_t elem2)
692 {
693 return rec_mset_elem_equal_fn ((void *) elem1,
694 (void *) elem2);
695 }
696
697 void *
rec_mset_elem_dup_data(rec_mset_elem_t elem)698 rec_mset_elem_dup_data (rec_mset_elem_t elem)
699 {
700 return elem->mset->dup_fn[elem->type] (elem->data);
701 }
702
703 void
rec_mset_dump(rec_mset_t mset)704 rec_mset_dump (rec_mset_t mset)
705 {
706 gl_list_iterator_t iter;
707 gl_list_node_t node;
708 rec_mset_elem_t elem;
709 int i;
710
711 printf ("MSET:\n");
712 printf (" ntypes: %d\n", mset->ntypes);
713
714 for (i = 0; i < mset->ntypes; i++)
715 {
716 printf(" type %d:\n", i);
717 printf(" count: %zd\n", mset->count[i]);
718 printf(" disp_fn: %p\n", mset->disp_fn[i]);
719 printf(" equal_fn: %p\n", mset->equal_fn[i]);
720 printf(" dup_fn: %p\n", mset->dup_fn[i]);
721 }
722
723 printf(" nodes:\n");
724 iter = gl_list_iterator (mset->elem_list);
725 while (gl_list_iterator_next (&iter, (const void **) &elem, &node))
726 {
727 printf(" node=%p elem=%p elem->type=%d elem->data=%p contained=%p\n", node, elem,
728 elem->type, elem->data, elem->mset);
729 i++;
730 }
731
732 printf("END MSET\n");
733 }
734
735 rec_mset_elem_t
rec_mset_add_sorted(rec_mset_t mset,rec_mset_type_t type,void * data)736 rec_mset_add_sorted (rec_mset_t mset,
737 rec_mset_type_t type,
738 void *data)
739 {
740 rec_mset_elem_t elem;
741 gl_list_node_t node;
742
743 /* Create the mset element to insert in the gl_list, returning NULL
744 if there is no enough memory. */
745
746 elem = rec_mset_elem_new (mset, type, data);
747 if (!elem)
748 {
749 return NULL;
750 }
751
752 /* Insert the element at the proper place in the list. */
753
754 node = gl_sortedlist_nx_add (mset->elem_list,
755 rec_mset_elem_compare_fn,
756 (void *) elem);
757 if (!node)
758 {
759 rec_mset_elem_destroy (elem);
760 return NULL;
761 }
762
763 elem->list_node = node;
764
765 mset->count[0]++;
766 if (elem->type != MSET_ANY)
767 {
768 mset->count[elem->type]++;
769 }
770
771 return elem;
772 }
773
774 /*
775 * Private functions.
776 */
777
778 static void
rec_mset_init(rec_mset_t mset)779 rec_mset_init (rec_mset_t mset)
780 {
781 /* Initialize the mset structure so it can be safely passed to
782 rec_mset_destroy even if its contents are not completely
783 initialized with real values. */
784
785 memset (mset, 0 /* NULL */, sizeof (struct rec_mset_s));
786 }
787
788 static bool
rec_mset_elem_equal_fn(const void * e1,const void * e2)789 rec_mset_elem_equal_fn (const void *e1,
790 const void *e2)
791 {
792 rec_mset_elem_t elem1;
793 rec_mset_elem_t elem2;
794
795 elem1 = (rec_mset_elem_t) e1;
796 elem2 = (rec_mset_elem_t) e2;
797
798 if ((elem1->mset != elem2->mset)
799 || (elem1->type != elem2->type))
800 {
801 return false;
802 }
803
804 return (elem1->mset->equal_fn[elem1->type]) (elem1->data,
805 elem2->data);
806 }
807
808 static void
rec_mset_elem_dispose_fn(const void * e)809 rec_mset_elem_dispose_fn (const void *e)
810 {
811 rec_mset_elem_t elem;
812
813 elem = (rec_mset_elem_t) e;
814 rec_mset_elem_destroy (elem);
815 }
816
817 static int
rec_mset_elem_compare_fn(const void * e1,const void * e2)818 rec_mset_elem_compare_fn (const void *e1,
819 const void *e2)
820 {
821 int result = 0;
822 rec_mset_elem_t elem1;
823 rec_mset_elem_t elem2;
824
825 elem1 = (rec_mset_elem_t) e1;
826 elem2 = (rec_mset_elem_t) e2;
827
828 if (elem1->mset->compare_fn)
829 {
830 result = (elem1->mset->compare_fn[elem1->type]) (elem1->data,
831 elem2->data,
832 elem2->type);
833 }
834
835 return result;
836 }
837
838 static rec_mset_list_iter_t
rec_mset_iter_gl2mset(gl_list_iterator_t list_iter)839 rec_mset_iter_gl2mset (gl_list_iterator_t list_iter)
840 {
841 rec_mset_list_iter_t mset_iter;
842
843 mset_iter.vtable = (void *) list_iter.vtable;
844 mset_iter.list = (void *) list_iter.list;
845 mset_iter.count = list_iter.count;
846 mset_iter.p = list_iter.p;
847 mset_iter.q = list_iter.q;
848 mset_iter.i = list_iter.i;
849 mset_iter.j = list_iter.j;
850
851 return mset_iter;
852 }
853
854 static gl_list_iterator_t
rec_mset_iter_mset2gl(rec_mset_list_iter_t mset_iter)855 rec_mset_iter_mset2gl (rec_mset_list_iter_t mset_iter)
856 {
857 gl_list_iterator_t list_iter;
858
859 list_iter.vtable = (const struct gl_list_implementation *) mset_iter.vtable;
860 list_iter.list = (gl_list_t) mset_iter.list;
861 list_iter.count = mset_iter.count;
862 list_iter.p = mset_iter.p;
863 list_iter.q = mset_iter.q;
864 list_iter.i = mset_iter.i;
865 list_iter.j = mset_iter.j;
866
867 return list_iter;
868 }
869
870 static rec_mset_elem_t
rec_mset_elem_new(rec_mset_t mset,rec_mset_type_t type,void * data)871 rec_mset_elem_new (rec_mset_t mset,
872 rec_mset_type_t type,
873 void *data)
874 {
875 rec_mset_elem_t new;
876
877 if (type >= mset->ntypes)
878 {
879 return NULL;
880 }
881
882 new = malloc (sizeof (struct rec_mset_elem_s));
883 if (new)
884 {
885 new->type = type;
886 new->data = data;
887 new->mset = mset;
888 new->list_node = NULL;
889 }
890
891 return new;
892 }
893
894 static void
rec_mset_elem_destroy(rec_mset_elem_t elem)895 rec_mset_elem_destroy (rec_mset_elem_t elem)
896 {
897 if (elem)
898 {
899 /* Dispose the data stored in the element if a disposal callback
900 function was configured by the user. The callback is never
901 invoked if the stored data is NULL. */
902
903 if (elem->data && elem->mset->disp_fn[elem->type])
904 {
905 elem->mset->disp_fn[elem->type] (elem->data);
906 }
907
908 free (elem);
909 }
910 }
911
912 /* End of rec-mset.c */
913