/************************************************************************ Randomize the elements of a genlist using the Fisher-Yates shuffle. see: genlist_sort() and shared.c:array_shuffle() ************************************************************************/ void genlist_shuffle(struct genlist *pgenlist) { const int n = genlist_size(pgenlist); void *sortbuf[n]; struct genlist_link *myiter; int i, shuffle[n]; if (n <= 1) { return; } myiter = find_genlist_position(pgenlist, 0); for (i = 0; i < n; i++, myiter = myiter->next) { sortbuf[i] = myiter->dataptr; /* also create the shuffle list */ shuffle[i] = i; } /* randomize it */ array_shuffle(shuffle, n); /* create the shuffled list */ myiter = find_genlist_position(pgenlist, 0); for (i = 0; i < n; i++, myiter = myiter->next) { myiter->dataptr = sortbuf[shuffle[i]]; } }
/************************************************************************ Returns the user-data pointer stored in the genlist at the position given by 'idx'. For idx out of range (including an empty list), returns NULL. Recall 'idx' can be -1 meaning the last element. ************************************************************************/ void *genlist_get(const struct genlist *pgenlist, int idx) { struct genlist_link *link = find_genlist_position(pgenlist, idx); if (link) { return link->dataptr; } else { return NULL; } }
/************************************************************************ Sort the elements of a genlist. The comparison function should be a function usable by qsort; note that the const void * arguments to compar should really be "pointers to void*", where the void* being pointed to are the genlist dataptrs. That is, there are two levels of indirection. To do the sort we first construct an array of pointers corresponding the the genlist dataptrs, then sort those and put them back into the genlist. ************************************************************************/ void genlist_sort(struct genlist *pgenlist, int (*compar)(const void *, const void *)) { const int n = genlist_size(pgenlist); void *sortbuf[n]; struct genlist_link *myiter; int i; if (n <= 1) { return; } myiter = find_genlist_position(pgenlist, 0); for (i = 0; i < n; i++, myiter = myiter->next) { sortbuf[i] = myiter->dataptr; } qsort(sortbuf, n, sizeof(*sortbuf), compar); myiter = find_genlist_position(pgenlist, 0); for (i = 0; i < n; i++, myiter = myiter->next) { myiter->dataptr = sortbuf[i]; } }
/************************************************************************ ... ************************************************************************/ void genlist_insert(struct genlist *pgenlist, void *data, int pos) { if(!pgenlist->nelements) { /*list is empty, ignore pos */ struct genlist_link *plink=(struct genlist_link *) malloc(sizeof(struct genlist_link)); plink->dataptr=data; plink->next=&pgenlist->null_link; plink->prev=&pgenlist->null_link; pgenlist->head_link=plink; pgenlist->tail_link=plink; } else { struct genlist_link *plink=(struct genlist_link *) malloc(sizeof(struct genlist_link)); plink->dataptr=data; if(pos==0) { plink->next=pgenlist->head_link; plink->prev=&pgenlist->null_link; pgenlist->head_link->prev=plink; pgenlist->head_link=plink; } else if(pos==-1) { plink->next=&pgenlist->null_link; plink->prev=pgenlist->tail_link; pgenlist->tail_link->next=plink; pgenlist->tail_link=plink; } else { struct genlist_link *pre_insert_link; pre_insert_link=find_genlist_position(pgenlist, pos); pre_insert_link->next->prev=plink; } } pgenlist->nelements++; }
/************************************************************************ Insert a new element in the list, at position 'pos', with the specified user-data pointer 'data'. Existing elements at >= pos are moved one space to the "right". Recall 'pos' can be -1 meaning add at the end of the list. For an empty list pos has no effect. A bad 'pos' value for a non-empty list is treated as -1 (is this a good idea?) ************************************************************************/ static void genlist_insert(struct genlist *pgenlist, void *data, int pos) { if (pgenlist->nelements == 0) { /*list is empty, ignore pos */ struct genlist_link *plink = fc_malloc(sizeof(*plink)); plink->dataptr = data; plink->next = NULL; plink->prev = NULL; pgenlist->head_link = plink; pgenlist->tail_link = plink; } else { struct genlist_link *plink = fc_malloc(sizeof(*plink)); plink->dataptr = data; if (pos == 0) { plink->next = pgenlist->head_link; plink->prev = NULL; pgenlist->head_link->prev = plink; pgenlist->head_link = plink; } else if (pos <= -1 || pos >= pgenlist->nelements) { plink->next = NULL; plink->prev = pgenlist->tail_link; pgenlist->tail_link->next = plink; pgenlist->tail_link = plink; } else { struct genlist_link *left, *right; /* left and right of new element */ right = find_genlist_position(pgenlist, pos); left = right->prev; plink->next = right; plink->prev = left; right->prev = plink; left->next = plink; } } pgenlist->nelements++; }
/************************************************************************ ... ************************************************************************/ void *genlist_get(struct genlist *pgenlist, int idx) { struct genlist_link *link=find_genlist_position(pgenlist, idx); return link->dataptr; }
/************************************************************************ ... ************************************************************************/ void genlist_iterator_init(struct genlist_iterator *iter, struct genlist *pgenlist, int pos) { iter->list=pgenlist; iter->link=find_genlist_position(pgenlist, pos); }