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