xref: /qemu/util/range.c (revision 6dd726a2)
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