Mercurial > illumos > onarm
view usr/src/cmd/lvm/metassist/common/volume_dlist.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
line wrap: on
line source
/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "@(#)volume_dlist.c 1.2 05/06/08 SMI" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include "volume_dlist.h" #define _volume_dlist_C /* * public constant definitions */ const boolean_t ASCENDING = TRUE; /* list ordering */ const boolean_t DESCENDING = FALSE; const boolean_t AT_TAIL = TRUE; /* list insertion location */ const boolean_t AT_HEAD = FALSE; /* * determine if the list contains an item * that points at the object */ boolean_t dlist_contains( dlist_t *list, void *obj, int (compare)(void *, void *)) { return (dlist_find(list, obj, compare) != NULL); } /* * locate the item in the list that points at the object */ dlist_t * dlist_find( dlist_t *list, void *obj, int (compare)(void *, void *)) { dlist_t *iter; for (iter = list; iter != NULL; iter = iter->next) { if ((compare)(obj, iter->obj) == 0) { return (iter); } } return (NULL); } /* * insert item into list in the desired order (ascending or descending) * using the comparison function provided. * * In the for loop, iter marks current position in the list * and item is the item to be inserted. * * Iterate the list and find the correct place to insert temp. * * if (ascending && compare(item, iter) <= 0 || * (descending && compare(item, iter) >= 0) * item goes before iter * else * item goes after iter */ dlist_t * dlist_insert_ordered( dlist_t *item, dlist_t *list, boolean_t ascending, int (compare)(void *, void *)) { dlist_t *head = NULL; dlist_t *iter = NULL; int result = 0; if (list == NULL) { head = item; } else { head = list; for (iter = list; iter != NULL; iter = iter->next) { result = (compare)(item->obj, iter->obj); if ((ascending && (result <= 0)) || (!ascending && (result >= 0))) { if (iter == head) { head = item; item->next = iter; iter->prev = item; } else { item->prev = iter->prev; item->prev->next = item; iter->prev = item; item->next = iter; } break; } if (iter->next == NULL) { /* end of list, so item becomes the new end */ iter->next = item; item->prev = iter; break; } } } return (head); } /* * Remove the first node pointing to same content as item from list, * clear it's next and prev pointers, return new list head. * * The caller is responsible for freeing the removed item if it is no * longer needed. * * The comparison function should be of the form: * * int compare(void *obj1, void* obj2); * * When called, obj1 will be the object passed into * dlist_remove_equivalent_item and obj2 will be an object pointed to * by an item in the list. * * The function should return 0 if the two objects are equivalent The * function should return nonzero otherwise * * @param list * the list containing the item to remove * * @param obj * the object with which to compare each item * * @param compare * the comparison function, passed obj and the obj member * of each item, to return 0 if item should be removed * * @param removed * RETURN: the removed item, or NULL if none was found * * @return the first element of the resulting list */ dlist_t * dlist_remove_equivalent_item( dlist_t *list, void *obj, int (compare)(void *, void *), dlist_t **removed) { dlist_t *item; *removed = NULL; if (list == NULL) { return (list); } item = dlist_find(list, obj, compare); if (item == NULL) { return (list); } *removed = item; return (dlist_remove(item)); } /* * Remove an item from its list. Return the resulting list. * * @param item * the item to remove, with prev and next pointers * set to NULL * * @return the first element of the resulting list */ dlist_t * dlist_remove( dlist_t *item) { dlist_t *head = NULL; if (item != NULL) { if (item->next != NULL) { item->next->prev = item->prev; head = item->next; } if (item->prev != NULL) { item->prev->next = item->next; head = item->prev; } item->next = NULL; item->prev = NULL; /* Find head of list */ for (; head != NULL && head->prev != NULL; head = head->prev); } return (head); } /* * append item to list, either beginning or end */ dlist_t * dlist_append( dlist_t *item, dlist_t *list, boolean_t attail) { dlist_t *head = list; if (list == NULL) { head = item; } else if (item == NULL) { head = list; } else if (attail) { dlist_t *iter; /* append to end */ for (iter = head; iter->next != NULL; iter = iter->next); iter->next = item; item->prev = iter; } else { /* insert at begining */ item->next = head; head->prev = item; head = item; } return (head); } /* * Create a dlist_t element for the given object and append to list. * * @param object * the obj member of the dlist_t element to be created * * @param list * the list to which to append the new dlist_t element * * @param attail * whether to append at the beginning (AT_HEAD) or end * (AT_TAIL) of the list * * @return 0 * if successful * * @return ENOMEM * if a dlist_t could not be allocated */ int dlist_append_object( void *object, dlist_t **list, boolean_t attail) { dlist_t *item = dlist_new_item(object); if (item == NULL) { return (ENOMEM); } *list = dlist_append(item, *list, attail); return (0); } /* * Appends list2 to the end of list1. * * Returns the resulting list. */ dlist_t * dlist_append_list( dlist_t *list1, dlist_t *list2) { dlist_t *iter; if (list1 == NULL) { return (list2); } if (list2 != NULL) { /* Find last element of list1 */ for (iter = list1; iter->next != NULL; iter = iter->next); iter->next = list2; list2->prev = iter; } return (list1); } /* * compute number of items in list */ int dlist_length( dlist_t *list) { dlist_t *iter; int length = 0; for (iter = list; iter != NULL; iter = iter->next) ++length; return (length); } /* * Allocate a new dlist_t structure and initialize the opaque object * pointer the input object. * * @return A new dlist_t structure for the given object, or NULL * if the memory could not be allocated. */ dlist_t * dlist_new_item( void *obj) { dlist_t *item = (dlist_t *)calloc(1, sizeof (dlist_t)); if (item != NULL) { item->obj = obj; } return (item); } /* * Traverse the list pointed to by head and free each * list node. If freefunc is non-NULL, call freefunc * for each node's object. */ void dlist_free_items( dlist_t *head, void (freefunc(void *))) { while (head != NULL) { dlist_t *item = head; head = head->next; if (freefunc != NULL) { freefunc(item->obj); } free((void *) item); } } /* * Order the given list such that the number of similar elements * adjacent to each other are minimized. * * The algorithm is: * * 1. Sort similar items into categories. Two elements are considered * similar if the given compare function returns 0. * * 2. Create a new list by iterating through each category and * selecting an element from the category with the most elements. * Avoid choosing an element from the last category chosen. * * @param list * the list to order * * @param compare * the comparison function, passed the obj members * of two items, to return 0 if the items can be * considered similar * * @return the first element of the resulting list */ dlist_t * dlist_separate_similar_elements( dlist_t *list, int(compare)(void *, void *)) { dlist_t **categories = NULL; dlist_t *item; int ncategories = 0; int max_elements; int lastcat; /* * First, sort like items into categories, according to * the passed-in compare function */ for (item = list; item != NULL; ) { dlist_t *removed; /* Remove this item from the list */ list = dlist_remove(item); /* Create new category */ categories = (dlist_t **)realloc( categories, ++ncategories * sizeof (dlist_t *)); categories[ncategories - 1] = item; /* Add like items to same category */ list = dlist_remove_equivalent_item( list, item->obj, compare, &removed); while (removed != NULL) { /* Add removed item to category */ dlist_append(removed, item, AT_TAIL); list = dlist_remove_equivalent_item( list, item->obj, compare, &removed); } item = list; } /* * Next, create a new list, minimizing the number of adjacent * elements from the same category */ list = NULL; lastcat = -1; do { int i; int curcat; /* * Find the category with the most elements, other than * the last category chosen */ max_elements = 0; for (i = 0; i < ncategories; i++) { int nelements; if (i == lastcat) { continue; } nelements = dlist_length(categories[i]); if (nelements > max_elements) { max_elements = nelements; curcat = i; } } /* If no elements were found, use the last category chosen */ if (max_elements == 0 && lastcat >= 0) { max_elements = dlist_length(categories[lastcat]); curcat = lastcat; } /* Was a category with elements found? */ if (max_elements != 0) { /* Remove first element of chosen category */ item = categories[curcat]; categories[curcat] = dlist_remove(item); /* Add removed element to resulting list */ list = dlist_append(item, list, AT_TAIL); lastcat = curcat; } } while (max_elements != 0); free(categories); return (list); }