diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/lvm/metassist/common/volume_dlist.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,512 @@
+/*
+ * 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);
+}