1fec0fc0aSEric Blake /* 2fec0fc0aSEric Blake * QEMU 64-bit address ranges 3fec0fc0aSEric Blake * 4fec0fc0aSEric Blake * Copyright (c) 2015-2016 Red Hat, Inc. 5fec0fc0aSEric Blake * 6fec0fc0aSEric Blake * This library is free software; you can redistribute it and/or 7fec0fc0aSEric Blake * modify it under the terms of the GNU General Public 8fec0fc0aSEric Blake * License as published by the Free Software Foundation; either 9fec0fc0aSEric Blake * version 2 of the License, or (at your option) any later version. 10fec0fc0aSEric Blake * 11fec0fc0aSEric Blake * This library is distributed in the hope that it will be useful, 12fec0fc0aSEric Blake * but WITHOUT ANY WARRANTY; without even the implied warranty of 13fec0fc0aSEric Blake * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14fec0fc0aSEric Blake * Lesser General Public License for more details. 15fec0fc0aSEric Blake * 16fec0fc0aSEric Blake * You should have received a copy of the GNU General Public 17fec0fc0aSEric Blake * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18fec0fc0aSEric Blake * 19fec0fc0aSEric Blake */ 20fec0fc0aSEric Blake 21fec0fc0aSEric Blake #include "qemu/osdep.h" 22fec0fc0aSEric Blake #include "qemu/range.h" 23fec0fc0aSEric Blake 24fec0fc0aSEric Blake /* 25*6dd726a2SMarkus Armbruster * Return -1 if @a < @b, 1 @a > @b, and 0 if they touch or overlap. 26*6dd726a2SMarkus Armbruster * Both @a and @b must not be empty. 27fec0fc0aSEric Blake */ 28db486cc3SEric Blake static inline int range_compare(Range *a, Range *b) 29fec0fc0aSEric Blake { 30*6dd726a2SMarkus Armbruster assert(!range_is_empty(a) && !range_is_empty(b)); 31*6dd726a2SMarkus Armbruster 32*6dd726a2SMarkus Armbruster /* Careful, avoid wraparound */ 33*6dd726a2SMarkus Armbruster if (b->lob && b->lob - 1 > a->upb) { 347c47959dSEric Blake return -1; 35db486cc3SEric Blake } 36*6dd726a2SMarkus Armbruster if (a->lob && a->lob - 1 > b->upb) { 377c47959dSEric Blake return 1; 387c47959dSEric Blake } 39db486cc3SEric Blake return 0; 407c47959dSEric Blake } 417c47959dSEric Blake 42db486cc3SEric Blake /* Insert @data into @list of ranges; caller no longer owns @data */ 437c47959dSEric Blake GList *range_list_insert(GList *list, Range *data) 44fec0fc0aSEric Blake { 45db486cc3SEric Blake GList *l; 46fec0fc0aSEric Blake 47a0efbf16SMarkus Armbruster assert(!range_is_empty(data)); 48db486cc3SEric Blake 49db486cc3SEric Blake /* Skip all list elements strictly less than data */ 50db486cc3SEric Blake for (l = list; l && range_compare(l->data, data) < 0; l = l->next) { 51fec0fc0aSEric Blake } 52fec0fc0aSEric Blake 53db486cc3SEric Blake if (!l || range_compare(l->data, data) > 0) { 54db486cc3SEric Blake /* Rest of the list (if any) is strictly greater than @data */ 55db486cc3SEric Blake return g_list_insert_before(list, l, data); 56fec0fc0aSEric Blake } 57fec0fc0aSEric Blake 58db486cc3SEric Blake /* Current list element overlaps @data, merge the two */ 59db486cc3SEric Blake range_extend(l->data, data); 60db486cc3SEric Blake g_free(data); 61db486cc3SEric Blake 62db486cc3SEric Blake /* Merge any subsequent list elements that now also overlap */ 63db486cc3SEric Blake while (l->next && range_compare(l->data, l->next->data) == 0) { 64db486cc3SEric Blake GList *new_l; 65db486cc3SEric Blake 66db486cc3SEric Blake range_extend(l->data, l->next->data); 67db486cc3SEric Blake g_free(l->next->data); 68db486cc3SEric Blake new_l = g_list_delete_link(list, l->next); 69db486cc3SEric Blake assert(new_l == list); 70fec0fc0aSEric Blake } 71fec0fc0aSEric Blake 72fec0fc0aSEric Blake return list; 73fec0fc0aSEric Blake } 74