diff --git a/qemu/glib_compat.c b/qemu/glib_compat.c index ee2568a4..a6164966 100644 --- a/qemu/glib_compat.c +++ b/qemu/glib_compat.c @@ -283,6 +283,107 @@ GList *g_list_sort (GList *list, GCompareFunc compare_func) return g_list_sort_real (list, (GFunc) compare_func, NULL); } +static inline GList* +_g_list_remove_link (GList *list, + GList *link) +{ + if (link) + { + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + + if (link == list) + list = list->next; + + link->next = NULL; + link->prev = NULL; + } + + return list; +} + +/** + * g_list_delete_link: + * @list: a #GList, this must point to the top of the list + * @link_: node to delete from @list + * + * Removes the node link_ from the list and frees it. + * Compare this to g_list_remove_link() which removes the node + * without freeing it. + * + * Returns: the (possibly changed) start of the #GList + */ +GList * +g_list_delete_link (GList *list, + GList *link_) +{ + list = _g_list_remove_link (list, link_); + //_g_list_free1 (link_); + g_free (link_); + + return list; +} + +/** + * g_list_insert_before: + * @list: a pointer to a #GList + * @sibling: the list element before which the new element + * is inserted or %NULL to insert at the end of the list + * @data: the data for the new element + * + * Inserts a new element into the list before the given position. + * + * Returns: the new start of the #GList + */ +GList* +g_list_insert_before (GList *list, + GList *sibling, + gpointer data) +{ + if (!list) + { + list = g_malloc(sizeof(GList)); + list->data = data; + return list; + } + else if (sibling) + { + GList *node; + + node = g_malloc(sizeof(GList)); + node->data = data; + node->prev = sibling->prev; + node->next = sibling; + sibling->prev = node; + if (node->prev) + { + node->prev->next = node; + return list; + } + else + { + return node; + } + } + else + { + GList *last; + + last = list; + while (last->next) + last = last->next; + + last->next = g_malloc(sizeof(GList)); + last->next->data = data; + last->next->prev = last; + last->next->next = NULL; + + return list; + } +} + /* END of g_list related functions */ /* Singly-linked list */ diff --git a/qemu/include/glib_compat.h b/qemu/include/glib_compat.h index 9a9a82a2..2e24ccdc 100644 --- a/qemu/include/glib_compat.h +++ b/qemu/include/glib_compat.h @@ -71,10 +71,12 @@ typedef struct _GList { GList *g_list_first(GList *list); void g_list_foreach(GList *list, GFunc func, gpointer user_data); void g_list_free(GList *list); +GList* g_list_insert_before(GList *list, GList *sibling, gpointer data); GList *g_list_insert_sorted(GList *list, gpointer data, GCompareFunc compare); #define g_list_next(list) (list->next) GList *g_list_prepend(GList *list, gpointer data); GList *g_list_remove_link(GList *list, GList *llink); +GList *g_list_delete_link (GList *list, GList *link_); GList *g_list_sort(GList *list, GCompareFunc compare); typedef struct _GSList { diff --git a/qemu/util/range.c b/qemu/util/range.c index dd460926..e90c988d 100644 --- a/qemu/util/range.c +++ b/qemu/util/range.c @@ -28,65 +28,48 @@ * - this can not represent a full 0 to ~0x0LL range. */ -/* 0,1 can merge with 1,2 but don't overlap */ -static bool ranges_can_merge(Range *range1, Range *range2) +/* Return -1 if @a < @b, 1 if greater, and 0 if they touch or overlap. */ +static inline int range_compare(Range *a, Range *b) { - return !(range1->end < range2->begin || range2->end < range1->begin); -} - -static void range_merge(Range *range1, Range *range2) -{ - if (range1->end < range2->end) { - range1->end = range2->end; - } - if (range1->begin > range2->begin) { - range1->begin = range2->begin; - } -} - -static gint range_compare(gconstpointer a, gconstpointer b) -{ - Range *ra = (Range *)a, *rb = (Range *)b; - if (ra->begin == rb->begin && ra->end == rb->end) { - return 0; - } else if (range_get_last(ra->begin, ra->end) < - range_get_last(rb->begin, rb->end)) { + /* Zero a->end is 2**64, and therefore not less than any b->begin */ + if (a->end && a->end < b->begin) { return -1; - } else { + } + if (b->end && a->begin > b->end) { return 1; } + return 0; } +/* Insert @data into @list of ranges; caller no longer owns @data */ GList *range_list_insert(GList *list, Range *data) { - GList *l, *next = NULL; - Range *r, *nextr; + GList *l; - if (!list) { - list = g_list_insert_sorted(list, data, range_compare); - return list; + /* Range lists require no empty ranges */ + assert(data->begin < data->end || (data->begin && !data->end)); + + /* Skip all list elements strictly less than data */ + for (l = list; l && range_compare(l->data, data) < 0; l = l->next) { } - nextr = data; - l = list; - while (l && l != next && nextr) { - r = l->data; - if (ranges_can_merge(r, nextr)) { - range_merge(r, nextr); - l = g_list_remove_link(l, next); - next = g_list_next(l); - if (next) { - nextr = next->data; - } else { - nextr = NULL; - } - } else { - l = g_list_next(l); - } + if (!l || range_compare(l->data, data) > 0) { + /* Rest of the list (if any) is strictly greater than @data */ + return g_list_insert_before(list, l, data); } - if (!l) { - list = g_list_insert_sorted(list, data, range_compare); + /* Current list element overlaps @data, merge the two */ + range_extend(l->data, data); + g_free(data); + + /* Merge any subsequent list elements that now also overlap */ + while (l->next && range_compare(l->data, l->next->data) == 0) { + GList *new_l; + + range_extend(l->data, l->next->data); + g_free(l->next->data); + new_l = g_list_delete_link(list, l->next); + assert(new_l == list); } return list;