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 /* 25fec0fc0aSEric Blake * Operations on 64 bit address ranges. 26fec0fc0aSEric Blake * Notes: 27fec0fc0aSEric Blake * - ranges must not wrap around 0, but can include the last byte ~0x0LL. 28fec0fc0aSEric Blake * - this can not represent a full 0 to ~0x0LL range. 29fec0fc0aSEric Blake */ 30fec0fc0aSEric Blake 31*db486cc3SEric Blake /* Return -1 if @a < @b, 1 if greater, and 0 if they touch or overlap. */ 32*db486cc3SEric Blake static inline int range_compare(Range *a, Range *b) 33fec0fc0aSEric Blake { 34*db486cc3SEric Blake /* Zero a->end is 2**64, and therefore not less than any b->begin */ 35*db486cc3SEric Blake if (a->end && a->end < b->begin) { 367c47959dSEric Blake return -1; 37*db486cc3SEric Blake } 38*db486cc3SEric Blake if (b->end && a->begin > b->end) { 397c47959dSEric Blake return 1; 407c47959dSEric Blake } 41*db486cc3SEric Blake return 0; 427c47959dSEric Blake } 437c47959dSEric Blake 44*db486cc3SEric Blake /* Insert @data into @list of ranges; caller no longer owns @data */ 457c47959dSEric Blake GList *range_list_insert(GList *list, Range *data) 46fec0fc0aSEric Blake { 47*db486cc3SEric Blake GList *l; 48fec0fc0aSEric Blake 49*db486cc3SEric Blake /* Range lists require no empty ranges */ 50*db486cc3SEric Blake assert(data->begin < data->end || (data->begin && !data->end)); 51*db486cc3SEric Blake 52*db486cc3SEric Blake /* Skip all list elements strictly less than data */ 53*db486cc3SEric Blake for (l = list; l && range_compare(l->data, data) < 0; l = l->next) { 54fec0fc0aSEric Blake } 55fec0fc0aSEric Blake 56*db486cc3SEric Blake if (!l || range_compare(l->data, data) > 0) { 57*db486cc3SEric Blake /* Rest of the list (if any) is strictly greater than @data */ 58*db486cc3SEric Blake return g_list_insert_before(list, l, data); 59fec0fc0aSEric Blake } 60fec0fc0aSEric Blake 61*db486cc3SEric Blake /* Current list element overlaps @data, merge the two */ 62*db486cc3SEric Blake range_extend(l->data, data); 63*db486cc3SEric Blake g_free(data); 64*db486cc3SEric Blake 65*db486cc3SEric Blake /* Merge any subsequent list elements that now also overlap */ 66*db486cc3SEric Blake while (l->next && range_compare(l->data, l->next->data) == 0) { 67*db486cc3SEric Blake GList *new_l; 68*db486cc3SEric Blake 69*db486cc3SEric Blake range_extend(l->data, l->next->data); 70*db486cc3SEric Blake g_free(l->next->data); 71*db486cc3SEric Blake new_l = g_list_delete_link(list, l->next); 72*db486cc3SEric Blake assert(new_l == list); 73fec0fc0aSEric Blake } 74fec0fc0aSEric Blake 75fec0fc0aSEric Blake return list; 76fec0fc0aSEric Blake } 77