mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-24 20:26:46 +00:00
range: Eliminate direct Range member access
Users of struct Range mess liberally with its members, which makes refactoring hard. Create a set of methods, and convert all users to call them instead of accessing members. The methods have carefully worded contracts, and use assertions to check them. Backports commit a0efbf16604770b9d805bcf210ec29942321134f from qemu
This commit is contained in:
parent
fbb0645fb3
commit
8b2a0c4ece
|
@ -38,12 +38,93 @@ struct Range {
|
||||||
uint64_t end; /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */
|
uint64_t end; /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void range_invariant(Range *range)
|
||||||
|
{
|
||||||
|
assert((!range->begin && !range->end) /* empty */
|
||||||
|
|| range->begin <= range->end - 1); /* non-empty */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compound literal encoding the empty range */
|
||||||
|
// Unicorn: MSVC is in the stone-age and not C99/C11 compliant
|
||||||
|
//#define range_empty ((Range){ .begin = 0, .end = 0 })
|
||||||
|
|
||||||
|
/* Is @range empty? */
|
||||||
|
static inline bool range_is_empty(Range *range)
|
||||||
|
{
|
||||||
|
range_invariant(range);
|
||||||
|
return !range->begin && !range->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does @range contain @val? */
|
||||||
|
static inline bool range_contains(Range *range, uint64_t val)
|
||||||
|
{
|
||||||
|
return !range_is_empty(range)
|
||||||
|
&& val >= range->begin && val <= range->end - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize @range to the empty range */
|
||||||
|
static inline void range_make_empty(Range *range)
|
||||||
|
{
|
||||||
|
range->begin = 0;
|
||||||
|
range->end = 0;
|
||||||
|
assert(range_is_empty(range));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize @range to span the interval [@lob,@upb].
|
||||||
|
* Both bounds are inclusive.
|
||||||
|
* The interval must not be empty, i.e. @lob must be less than or
|
||||||
|
* equal @upb.
|
||||||
|
* The interval must not be [0,UINT64_MAX], because Range can't
|
||||||
|
* represent that.
|
||||||
|
*/
|
||||||
|
static inline void range_set_bounds(Range *range, uint64_t lob, uint64_t upb)
|
||||||
|
{
|
||||||
|
assert(lob <= upb);
|
||||||
|
range->begin = lob;
|
||||||
|
range->end = upb + 1; /* may wrap to zero, that's okay */
|
||||||
|
assert(!range_is_empty(range));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize @range to span the interval [@lob,@upb_plus1).
|
||||||
|
* The lower bound is inclusive, the upper bound is exclusive.
|
||||||
|
* Zero @upb_plus1 is special: if @lob is also zero, set @range to the
|
||||||
|
* empty range. Else, set @range to [@lob,UINT64_MAX].
|
||||||
|
*/
|
||||||
|
static inline void range_set_bounds1(Range *range,
|
||||||
|
uint64_t lob, uint64_t upb_plus1)
|
||||||
|
{
|
||||||
|
range->begin = lob;
|
||||||
|
range->end = upb_plus1;
|
||||||
|
range_invariant(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return @range's lower bound. @range must not be empty. */
|
||||||
|
static inline uint64_t range_lob(Range *range)
|
||||||
|
{
|
||||||
|
assert(!range_is_empty(range));
|
||||||
|
return range->begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return @range's upper bound. @range must not be empty. */
|
||||||
|
static inline uint64_t range_upb(Range *range)
|
||||||
|
{
|
||||||
|
assert(!range_is_empty(range));
|
||||||
|
return range->end - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extend @range to the smallest interval that includes @extend_by, too.
|
||||||
|
* This must not extend @range to cover the interval [0,UINT64_MAX],
|
||||||
|
* because Range can't represent that.
|
||||||
|
*/
|
||||||
static inline void range_extend(Range *range, Range *extend_by)
|
static inline void range_extend(Range *range, Range *extend_by)
|
||||||
{
|
{
|
||||||
if (!extend_by->begin && !extend_by->end) {
|
if (range_is_empty(extend_by)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!range->begin && !range->end) {
|
if (range_is_empty(range)) {
|
||||||
*range = *extend_by;
|
*range = *extend_by;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +135,8 @@ static inline void range_extend(Range *range, Range *extend_by)
|
||||||
if (range->end - 1 < extend_by->end - 1) {
|
if (range->end - 1 < extend_by->end - 1) {
|
||||||
range->end = extend_by->end;
|
range->end = extend_by->end;
|
||||||
}
|
}
|
||||||
|
/* Must not extend to { .begin = 0, .end = 0 }: */
|
||||||
|
assert(!range_is_empty(range));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get last byte of a range from offset + length.
|
/* Get last byte of a range from offset + length.
|
||||||
|
|
|
@ -59,8 +59,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
|
||||||
if (errno == 0 && endptr > str) {
|
if (errno == 0 && endptr > str) {
|
||||||
if (*endptr == '\0') {
|
if (*endptr == '\0') {
|
||||||
cur = g_malloc0(sizeof(*cur));
|
cur = g_malloc0(sizeof(*cur));
|
||||||
cur->begin = start;
|
range_set_bounds(cur, start, start);
|
||||||
cur->end = start + 1;
|
|
||||||
siv->ranges = range_list_insert(siv->ranges, cur);
|
siv->ranges = range_list_insert(siv->ranges, cur);
|
||||||
cur = NULL;
|
cur = NULL;
|
||||||
str = NULL;
|
str = NULL;
|
||||||
|
@ -73,16 +72,14 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
|
||||||
end < start + 65536)) {
|
end < start + 65536)) {
|
||||||
if (*endptr == '\0') {
|
if (*endptr == '\0') {
|
||||||
cur = g_malloc0(sizeof(*cur));
|
cur = g_malloc0(sizeof(*cur));
|
||||||
cur->begin = start;
|
range_set_bounds(cur, start, end);
|
||||||
cur->end = end + 1;
|
|
||||||
siv->ranges = range_list_insert(siv->ranges, cur);
|
siv->ranges = range_list_insert(siv->ranges, cur);
|
||||||
cur = NULL;
|
cur = NULL;
|
||||||
str = NULL;
|
str = NULL;
|
||||||
} else if (*endptr == ',') {
|
} else if (*endptr == ',') {
|
||||||
str = endptr + 1;
|
str = endptr + 1;
|
||||||
cur = g_malloc0(sizeof(*cur));
|
cur = g_malloc0(sizeof(*cur));
|
||||||
cur->begin = start;
|
range_set_bounds(cur, start, end);
|
||||||
cur->end = end + 1;
|
|
||||||
siv->ranges = range_list_insert(siv->ranges, cur);
|
siv->ranges = range_list_insert(siv->ranges, cur);
|
||||||
cur = NULL;
|
cur = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,8 +91,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
|
||||||
} else if (*endptr == ',') {
|
} else if (*endptr == ',') {
|
||||||
str = endptr + 1;
|
str = endptr + 1;
|
||||||
cur = g_malloc0(sizeof(*cur));
|
cur = g_malloc0(sizeof(*cur));
|
||||||
cur->begin = start;
|
range_set_bounds(cur, start, start);
|
||||||
cur->end = start + 1;
|
|
||||||
siv->ranges = range_list_insert(siv->ranges, cur);
|
siv->ranges = range_list_insert(siv->ranges, cur);
|
||||||
cur = NULL;
|
cur = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,7 +130,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size,
|
||||||
if (siv->cur_range) {
|
if (siv->cur_range) {
|
||||||
Range *r = siv->cur_range->data;
|
Range *r = siv->cur_range->data;
|
||||||
if (r) {
|
if (r) {
|
||||||
siv->cur = r->begin;
|
siv->cur = range_lob(r);
|
||||||
}
|
}
|
||||||
*list = g_malloc0(size);
|
*list = g_malloc0(size);
|
||||||
} else {
|
} else {
|
||||||
|
@ -156,7 +152,7 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint64_t)siv->cur < r->begin || (uint64_t)siv->cur >= r->end) {
|
if (!range_contains(r, siv->cur)) {
|
||||||
siv->cur_range = g_list_next(siv->cur_range);
|
siv->cur_range = g_list_next(siv->cur_range);
|
||||||
if (!siv->cur_range) {
|
if (!siv->cur_range) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -165,7 +161,7 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
|
||||||
if (!r) {
|
if (!r) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
siv->cur = r->begin;
|
siv->cur = range_lob(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
tail->next = g_malloc0(size);
|
tail->next = g_malloc0(size);
|
||||||
|
@ -208,7 +204,7 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
siv->cur = r->begin;
|
siv->cur = range_lob(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
*obj = siv->cur;
|
*obj = siv->cur;
|
||||||
|
|
|
@ -46,8 +46,7 @@ GList *range_list_insert(GList *list, Range *data)
|
||||||
{
|
{
|
||||||
GList *l;
|
GList *l;
|
||||||
|
|
||||||
/* Range lists require no empty ranges */
|
assert(!range_is_empty(data));
|
||||||
assert(data->begin < data->end || (data->begin && !data->end));
|
|
||||||
|
|
||||||
/* Skip all list elements strictly less than data */
|
/* Skip all list elements strictly less than data */
|
||||||
for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {
|
for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {
|
||||||
|
|
Loading…
Reference in a new issue