diff options
Diffstat (limited to 'include/qemu/range.h')
-rw-r--r-- | include/qemu/range.h | 103 |
1 files changed, 91 insertions, 12 deletions
diff --git a/include/qemu/range.h b/include/qemu/range.h index 3970f00089..f28f0c1825 100644 --- a/include/qemu/range.h +++ b/include/qemu/range.h @@ -26,32 +26,111 @@ /* * Operations on 64 bit address ranges. * Notes: - * - ranges must not wrap around 0, but can include the last byte ~0x0LL. - * - this can not represent a full 0 to ~0x0LL range. + * - Ranges must not wrap around 0, but can include UINT64_MAX. */ -/* A structure representing a range of addresses. */ struct Range { - uint64_t begin; /* First byte of the range, or 0 if empty. */ - uint64_t end; /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */ + /* + * Do not access members directly, use the functions! + * A non-empty range has @lob <= @upb. + * An empty range has @lob == @upb + 1. + */ + uint64_t lob; /* inclusive lower bound */ + uint64_t upb; /* inclusive upper bound */ }; +static inline void range_invariant(Range *range) +{ + assert(range->lob <= range->upb || range->lob == range->upb + 1); +} + +/* Compound literal encoding the empty range */ +#define range_empty ((Range){ .lob = 1, .upb = 0 }) + +/* Is @range empty? */ +static inline bool range_is_empty(Range *range) +{ + range_invariant(range); + return range->lob > range->upb; +} + +/* Does @range contain @val? */ +static inline bool range_contains(Range *range, uint64_t val) +{ + return val >= range->lob && val <= range->upb; +} + +/* Initialize @range to the empty range */ +static inline void range_make_empty(Range *range) +{ + *range = range_empty; + 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. + */ +static inline void range_set_bounds(Range *range, uint64_t lob, uint64_t upb) +{ + range->lob = lob; + range->upb = upb; + 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) +{ + if (!lob && !upb_plus1) { + *range = range_empty; + } else { + range->lob = lob; + range->upb = upb_plus1 - 1; + } + 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->lob; +} + +/* 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->upb; +} + +/* + * Extend @range to the smallest interval that includes @extend_by, too. + */ static inline void range_extend(Range *range, Range *extend_by) { - if (!extend_by->begin && !extend_by->end) { + if (range_is_empty(extend_by)) { return; } - if (!range->begin && !range->end) { + if (range_is_empty(range)) { *range = *extend_by; return; } - if (range->begin > extend_by->begin) { - range->begin = extend_by->begin; + if (range->lob > extend_by->lob) { + range->lob = extend_by->lob; } - /* Compare last byte in case region ends at ~0x0LL */ - if (range->end - 1 < extend_by->end - 1) { - range->end = extend_by->end; + if (range->upb < extend_by->upb) { + range->upb = extend_by->upb; } + range_invariant(range); } /* Get last byte of a range from offset + length. |