sets.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:8k
- /*
- * ProFTPD - FTP server daemon
- * Copyright (c) 1997, 1998 Public Flood Software
- *
- * 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- * Generic set manipulation
- *
- * TODO: Use a hash table to greatly speed up set manipulation on
- * large sets.
- *
- * HISTORY:
- *
- * 3/31/97: Flood-
- * Changed all memory allocation routines to be "pool" compliant
- * -- now requires "pool{.c,.h}".
- */
- #include "conf.h"
- #define POOL(x) ((x) ? (x) : permanent_pool)
- /* Create a new set, compf is a pointer to the function used
- to to compare members of the set ... it should return 1, 0, or
- -1 after the fashion of strcmp. Returns NULL if memory allocation
- fails.
- */
- xaset_t *xaset_create(pool *pool, XASET_COMPARE compf)
- {
- xaset_t *newset = palloc(POOL(pool),sizeof(xaset_t));
- if(!newset) return NULL;
- newset->xas_list = NULL;
- newset->mempool = POOL(pool);
- newset->xas_compare = compf;
- return newset;
- }
- /* Inserts a new member into an existing set. The member is inserted
- at the beginning of the set.
- Returns: 1 if successful
- 0 if one or more arguments is invalid or something
- is wrong with the set
- -1 error (not used)
- */
- int xaset_insert(xaset_t *set, xasetmember_t *member)
- {
- if(!set || !member)
- return 0;
- member->next = set->xas_list;
- if(set->xas_list)
- set->xas_list->prev = member;
- set->xas_list = member;
- return 1;
- }
- /* Inserts a new member into an existing set at the end
- * of the list.
- */
- int xaset_insert_end(xaset_t *set, xasetmember_t *member)
- {
- xasetmember_t **tmp,*prev = NULL;
- if(!set || !member)
- return 0;
- for(tmp = &set->xas_list; *tmp; prev=*tmp, tmp=&(*tmp)->next) ;
- *tmp = member;
- member->prev = prev;
- member->next = NULL;
- return 1;
- }
- /* Inserts a new member into an existing set, sorted using the set's
- compare callback. If dupes_allowed is non-0, returns 0 and the
- member is not added to the set. Otherwise, it is added immediately
- before the first dupelicate. If the set is not empty and not pre-
- sorted, results are undefined.
- Returns: 1 if successful
- 0 if bad arguments or duplicate member
- -1 error (not used, applicable error would be in errno)
- */
- int xaset_insert_sort(xaset_t *set, xasetmember_t *member, int dupes_allowed)
- {
- xasetmember_t **setp,*mprev = NULL;
- int c;
- if(!set || !member || !set->xas_compare)
- return 0;
- for(setp = &set->xas_list; *setp; setp=&(*setp)->next) {
- if((c = set->xas_compare(member,*setp)) <= 0) {
- if(c == 0 && !dupes_allowed)
- return 0;
- break;
- }
- mprev = *setp;
- }
- if(*setp)
- (*setp)->prev = member;
- member->prev = mprev;
- member->next = *setp;
- *setp = member;
- return 1;
- }
- /* Remove a member from a set. The set need not be sorted. Note that
- this does NOT free the memory used by the member. No check is performed
- to validate that `member' is truely a member of `set'.
- Returns: 1 if successful
- 0 if invalid args
- -1 error (check errno, unused at this time)
- */
- int xaset_remove(xaset_t *set, xasetmember_t *member)
- {
- if(!set || !member)
- return 0;
- if(member->prev)
- member->prev->next = member->next;
- else /* assume that member is first in the list */
- set->xas_list = member->next;
- if(member->next)
- member->next->prev = member->prev;
- member->next = member->prev = NULL;
- return 1;
- }
- /* Perform a set union. The two sets do not need to be sorted, however
- the returned new set will be. Duplicate entries are, as per
- normal set logic, removed. Return value is the new set, or
- NULL if out-of-memory or one or more arguments is invalid.
- */
- xaset_t *xaset_union(pool *pool,xaset_t *set1, xaset_t *set2,
- size_t msize, XASET_MCOPY copyf)
- {
- xaset_t *newset;
- xasetmember_t *setp,*n;
- xaset_t *setv[3];
- xaset_t **setcp;
- setv[0] = set1; setv[1] = set2; setv[2] = NULL;
- if(!set1 || !set2 || (!msize && !copyf))
- return NULL;
- pool = (pool ? pool : (set1->mempool ? set1->mempool : set2->mempool));
- if(!(newset = xaset_create(pool,set1->xas_compare)))
- return NULL;
-
- for(setcp = setv; *setcp; setcp++)
- for(setp = (*setcp)->xas_list; setp; setp=setp->next) {
- n = copyf ? copyf(setp) : (xasetmember_t*)palloc(pool,msize);
- if(!n)
- return NULL; /* Could cleanup here */
- if(!copyf)
- memcpy(n,setp,msize);
- if(xaset_insert_sort(newset,n,0) == -1)
- return NULL;
- }
- return newset;
- }
- /* Perform set subtraction: set1 - set2, creating a new set composed of
- all the elements in set1 that are not in set2. NULL is returned if
- a new set cannot be created (out-of-memory), or either set1 or set2
- are NULL. If the copyf argument is non-NULL it is used to copy each
- applicable element to the new set. If either of the two sets is
- unsorted, the result will be undefined. set1's comparison callback
- function is used when comparing members of each set.
- */
- xaset_t *xaset_subtract(pool *pool,xaset_t *set1, xaset_t *set2,
- size_t msize, XASET_MCOPY copyf)
- {
- xaset_t *newset;
- xasetmember_t *set1p,*set2p,*n,**pos;
- int c;
- if(!set1 || !set2 || (!msize && !copyf))
- return NULL;
- pool = (pool ? pool : (set1->mempool ? set1->mempool : set2->mempool));
- if(!(newset = xaset_create(pool,set1->xas_compare)))
- return NULL;
- pos = &newset->xas_list;
- /* NOTE: xaset_insert_sort is not used here for performance
- reasons. */
- for(set1p = set1->xas_list, set2p = set2->xas_list; set1p;
- set1p = set1p->next) {
- if(!set2p || (c = set1->xas_compare(set1p,set2p)) < 0) {
- /* Copy if set2 is exhausted or set1p's "value" is less than
- set2p's. */
- n = copyf ? copyf(set1p) : (xasetmember_t*)palloc(pool,msize);
- if(!n)
- return NULL; /* Could cleanup here */
- if(!copyf)
- memcpy(n,set1p,msize);
- /* Create links */
- n->prev = *pos;
- n->next = NULL;
- if(*pos)
- pos = &(*pos)->next;
- *pos = n;
- } else if(c >= 0) {
- /* Traverse set2 until we reach a point where set2 is
- exhausted or set2p is "greater" than set1p */
- while((set2p = set2p->next) != NULL &&
- set1->xas_compare(set1p,set2p) > 0) ;
- /* In case there are dupes in set1, examine the next (if any)
- value(s) and skip if necessary */
- while(set1p->next && set1->xas_compare(set1p,set1p->next) == 0)
- set1p = set1p->next;
- }
- }
- return newset;
- }
- /* Perform an exact copy of the entire set, returning the new set.
- msize specifies the size of each member. If copyf is non-NULL, it
- is called instead to copy each member.
- Returns NULL if out of memory condition occurs
- */
- xaset_t *xaset_copy(pool *pool, xaset_t *set, size_t msize, XASET_MCOPY copyf)
- {
- xaset_t *newset;
- xasetmember_t *n,*p,**pos;
- if(!copyf && !msize)
- return NULL;
- pool = (pool ? pool : set->mempool);
- if(!(newset = xaset_create(pool,set->xas_compare)))
- return NULL;
- pos = &newset->xas_list;
- /* NOTE: xaset_insert_sort is not used here for performance
- reasons. */
- for(p = set->xas_list; p; p=p->next) {
- n = copyf ? copyf(p) : (xasetmember_t*)palloc(pool,msize);
- if(!n)
- return NULL; /* Could clean up here */
- if(!copyf)
- memcpy(n,p,msize);
- /* Create links */
- n->prev = *pos;
- n->next = NULL;
- if(*pos)
- pos = &(*pos)->next;
- *pos = n;
- }
- return newset;
- }