/*----------------------------------------------------------------- SDCCset.c - contains support routines for sets Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ #include #include #include "newalloc.h" #include "SDCCset.h" /*-----------------------------------------------------------------*/ /* newSet - will allocate & return a new set entry */ /*-----------------------------------------------------------------*/ set * newSet (void) { set *lp; lp = Safe_alloc (sizeof (set)); lp->item = lp->curr = lp->next = NULL; return lp; } /*-----------------------------------------------------------------*/ /* setFromSet - creates a list from another list; the order of */ /* elements in new list is reverted */ /*-----------------------------------------------------------------*/ set * setFromSet (set * lp) { set *lfl = NULL; while (lp) { addSetHead (&lfl, lp->item); lp = lp->next; } return lfl; } /*-----------------------------------------------------------------*/ /* setFromSet - creates a list from another list; the order of */ /* elements in retained */ /*-----------------------------------------------------------------*/ set * setFromSetNonRev (set * lp) { set *lfl = NULL; while (lp) { addSet (&lfl, lp->item); lp = lp->next; } return lfl; } /*-----------------------------------------------------------------*/ /* isSetsEqual - are the lists equal, they are equal if they have */ /* the same objects & the same number of objects */ /*-----------------------------------------------------------------*/ int isSetsEqual (set * dest, set * src) { set *src1 = src; for (; dest && src; dest = dest->next, src = src->next) { if (!isinSet (src1, dest->item)) return 0; } if (!dest && !src) return 1; return 0; } /*-----------------------------------------------------------------*/ /* isSetsEqualWith - are the lists equal, they are equal if they */ /* have the same objects & the same number of */ /* objects , compare function */ /*-----------------------------------------------------------------*/ int isSetsEqualWith (set * dest, set * src, int (*cFunc) (void *, void *)) { set *src1 = src; for (; dest && src; dest = dest->next, src = src->next) { if (!isinSetWith (src1, dest->item, cFunc)) return 0; } if (!dest && !src) return 1; return 0; } /*-----------------------------------------------------------------*/ /* addSetIfnotP - adds to a linked list if not already present */ /*-----------------------------------------------------------------*/ void * addSetIfnotP (set ** list, void *item) { if (isinSet (*list, item)) return item; addSetHead (list, item); return item; } /*-----------------------------------------------------------------*/ /* addSetHead - add item to head of linked list */ /*-----------------------------------------------------------------*/ void * addSetHead (set ** list, void *item) { set *lp = newSet (); lp->item = item; lp->next = *list; assert (lp != lp->item); *list = lp; return item; } /*-----------------------------------------------------------------*/ /* addSet - add an item to a linear linked list */ /*-----------------------------------------------------------------*/ void * addSet (set ** list, void *item) { set *lp; /* item added to the tail of the list */ /* if the list is empty */ if (*list == NULL) { lp = *list = newSet (); } else { /* go to the end of the list */ for (lp = *list; lp->next; lp = lp->next); lp = lp->next = newSet (); } /* lp now all set */ lp->item = item; return item; } /*-----------------------------------------------------------------*/ /* deleteItemIf - will delete from set if cond function returns 1 */ /*-----------------------------------------------------------------*/ void deleteItemIf (set ** sset, int (*cond) (void *, va_list),...) { set *sp = *sset; va_list ap; while (sp) { /* * On the x86 va_list is just a pointer, so due to pass by value * ap is not mofified by the called function. On the PPC va_list * is a pointer to a structure, so ap is modified. Re-init each time. */ va_start (ap, cond); if ((*cond) (sp->item, ap)) { deleteSetItem (sset, sp->item); sp = *sset; continue; } va_end(ap); sp = sp->next; } } /*-----------------------------------------------------------------*/ /* deleteSetItem - will delete a given item from the list */ /*-----------------------------------------------------------------*/ void deleteSetItem (set ** list, void *item) { set *lp, *lp1; /* if list is empty */ if (*list == NULL) return; /* if this item is at the head of the list */ if ((*list)->item == item) { lp = *list; *list = (*list)->next; Safe_free (lp); return; } /* find the item in the list */ for (lp = *list; lp->next; lp = lp->next) { if (lp->next->item == item) { /* the next one is it */ lp1 = lp->next; /* this one will need to be freed */ lp->next = lp->next->next; /* take out of list */ Safe_free (lp1); return; } } /* could not find it */ } /*-----------------------------------------------------------------*/ /* isinSet - the item is present in the linked list */ /*-----------------------------------------------------------------*/ int isinSet (set * list, void *item) { set *lp; for (lp = list; lp; lp = lp->next) if (lp->item == item) return 1; return 0; } /*-----------------------------------------------------------------*/ /* isinSetWith - the item is present in the linked list */ /*-----------------------------------------------------------------*/ int isinSetWith (set * list, void *item, int (*cFunc) (void *, void *)) { set *lp; for (lp = list; lp; lp = lp->next) if ((*cFunc) (lp->item, item)) return 1; return 0; } /*-----------------------------------------------------------------*/ /* mergeSets - append list to sset */ /*-----------------------------------------------------------------*/ void mergeSets (set **sset, set *list) { if (*sset == NULL) { *sset = list; } else { set *lp; for (lp = *sset; lp->next; lp = lp->next) ; lp->next = list; } } /*-----------------------------------------------------------------*/ /* unionSets - will return the union of the two lists */ /*-----------------------------------------------------------------*/ set * unionSets (set * list1, set * list2, int throw) { set *un = NULL; set *lp; /* add all elements in the first list */ for (lp = list1; lp; lp = lp->next) addSet (&un, lp->item); /* now for all those in list2 which does not */ /* already exist in the list add */ for (lp = list2; lp; lp = lp->next) if (!isinSet (un, lp->item)) addSet (&un, lp->item); switch (throw) { case THROW_SRC: setToNull ((void *) &list2); break; case THROW_DEST: setToNull ((void *) &list1); break; case THROW_BOTH: setToNull ((void *) &list1); setToNull ((void *) &list2); } return un; } /*-----------------------------------------------------------------*/ /* unionSetsWith - will return the union of the two lists */ /*-----------------------------------------------------------------*/ set * unionSetsWith (set * list1, set * list2, int (*cFunc) (), int throw) { set *un = NULL; set *lp; /* add all elements in the first list */ for (lp = list1; lp; lp = lp->next) addSet (&un, lp->item); /* now for all those in list2 which does not */ /* already exist in the list add */ for (lp = list2; lp; lp = lp->next) if (!isinSetWith (un, lp->item, (int (*)(void *, void *)) cFunc)) addSet (&un, lp->item); switch (throw) { case THROW_SRC: setToNull ((void *) &list2); break; case THROW_DEST: setToNull ((void *) &list1); break; case THROW_BOTH: setToNull ((void *) &list1); setToNull ((void *) &list2); } return un; } /*-----------------------------------------------------------------*/ /* intersectSets - returns list of items in common to two lists */ /*-----------------------------------------------------------------*/ set * intersectSets (set * list1, set * list2, int throw) { set *in = NULL; set *lp; /* we can take any one of the lists and iterate over it */ for (lp = list1; lp; lp = lp->next) if (isinSet (list2, lp->item)) addSetHead (&in, lp->item); switch (throw) { case THROW_SRC: setToNull ((void *) &list2); break; case THROW_DEST: setToNull ((void *) &list1); break; case THROW_BOTH: setToNull ((void *) &list1); setToNull ((void *) &list2); } return in; } /*-----------------------------------------------------------------*/ /* intersectSetsWith - returns list of items in common to two */ /* lists */ /*-----------------------------------------------------------------*/ set * intersectSetsWith (set * list1, set * list2, int (*cFunc) (void *, void *), int throw) { set *in = NULL; set *lp; /* we can take any one of the lists and iterate over it */ for (lp = list1; lp; lp = lp->next) if (isinSetWith (list2, lp->item, cFunc)) addSetHead (&in, lp->item); switch (throw) { case THROW_SRC: setToNull ((void *) &list2); break; case THROW_DEST: setToNull ((void *) &list1); break; case THROW_BOTH: setToNull ((void *) &list1); setToNull ((void *) &list2); } return in; } /*-----------------------------------------------------------------*/ /* elementsInSet - elements count of a set */ /*-----------------------------------------------------------------*/ int elementsInSet (set * s) { set *loop = s; int count = 0; while (loop) { count++; loop = loop->next; } return count; } /*-----------------------------------------------------------------*/ /* indexSet - returns the i'th item in set */ /*-----------------------------------------------------------------*/ void * indexSet (set * s, int index) { set *loop=s; while(loop && index) { index--; loop = loop->next; } return (loop->item); } /*-----------------------------------------------------------------*/ /* reverseSet - reverse the order of the items of a set */ /*-----------------------------------------------------------------*/ set * reverseSet (set * s) { set *t = NULL; set *u = NULL; while(s->next) { t = s->next; s->next = u; u = s; s = t; } s->next = u; return s; } /*-----------------------------------------------------------------*/ /* subtractFromSet - take away from set1 elements of set2 */ /*-----------------------------------------------------------------*/ set * subtractFromSet (set * left, set * right, int throw) { set *result = setFromSet (left); set *loop; if (right) { for (loop = right; loop; loop = loop->next) if (isinSet (result, loop->item)) deleteSetItem (&result, loop->item); } switch (throw) { case THROW_SRC: setToNull ((void *) &right); break; case THROW_DEST: setToNull ((void *) &left); break; case THROW_BOTH: setToNull ((void *) &left); setToNull ((void *) &right); break; } return result; } /*-----------------------------------------------------------------*/ /* applyToSet - will call the supplied function with each item */ /*-----------------------------------------------------------------*/ int applyToSet (set * list, int (*somefunc) (void *, va_list),...) { set *lp; va_list ap; int rvalue = 0; for (lp = list; lp; lp = lp->next) { va_start (ap, somefunc); rvalue += (*somefunc) (lp->item, ap); va_end (ap); } return rvalue; } /*-----------------------------------------------------------------*/ /* applyToSetFTrue - will call the supplied function with each */ /* item until list is exhausted or a true is */ /* returned */ /*-----------------------------------------------------------------*/ int applyToSetFTrue (set * list, int (*somefunc) (void *, va_list),...) { set *lp; va_list ap; int rvalue = 0; for (lp = list; lp; lp = lp->next) { va_start (ap, somefunc); rvalue += (*somefunc) (lp->item, ap); va_end (ap); if (rvalue) break; } return rvalue; } /*-----------------------------------------------------------------*/ /* peekSet - will return the first element of the set */ /*-----------------------------------------------------------------*/ void * peekSet (set * sp) { if (!sp) return NULL; return sp->item; } /*-----------------------------------------------------------------*/ /* setFirstItem - gets the first item in the set, begins iteration */ /*-----------------------------------------------------------------*/ void * setFirstItem (set * sset) { if (sset) { sset->curr = sset; return sset->item; } return NULL; } /*-----------------------------------------------------------------*/ /* setNextItem - gets the next item, changes the iteration */ /*-----------------------------------------------------------------*/ void * setNextItem (set * sset) { if (sset && sset->curr) { sset->curr = sset->curr->next; if (sset->curr) return sset->curr->item; } return NULL; } /*-----------------------------------------------------------------*/ /* getSet - will delete & return the first item from the set */ /*-----------------------------------------------------------------*/ void * getSet (set ** list) { set *lp; void *item; /* if list is empty then we cannot delete */ if (*list == NULL) return (void *) NULL; /* find the item in the list */ lp = *list; item = lp->item; /* save the item */ *list = lp->next; return item; } /*-----------------------------------------------------------------*/ /* setToNull - will throw away the entire list */ /*-----------------------------------------------------------------*/ void setToNull (void **item) { if (!item) return; if (!*item) return; Safe_free (*item); *item = NULL; } /*-----------------------------------------------------------------*/ /* deleteSet - will throw away the entire list */ /* note - setToNull doesn't actually throw away the whole list. */ /* Instead it only throws away the first item. */ /*-----------------------------------------------------------------*/ void deleteSet (set **s) { set *curr; set *next; if(!s || !*s) return; curr = *s; next = curr->next; while (next) { Safe_free (curr); curr = next; next = next->next; } Safe_free (curr); *s = NULL; }