contiguous_mem/
range.rs

1#![doc(hidden)]
2
3use core::fmt::Display;
4
5/// Represents a range of bytes in
6/// [`AllocationTracker`](crate::tracker::AllocationTracker) and
7/// [`ContiguousMemoryStorage`](crate::ContiguousMemoryStorage).
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct ByteRange(
10    /// **Inclusive** lower bound of this byte range.
11    pub usize,
12    /// **Exclusive** upper bound of this byte range.
13    pub usize,
14);
15
16impl ByteRange {
17    /// Constructs a new byte range, ensuring that `from` and `to` are ordered
18    /// correctly.
19    pub fn new(from: usize, to: usize) -> Self {
20        ByteRange(from.min(to), to.max(from))
21    }
22
23    /// Constructs a new byte range without checking `from` and `to` ordering.
24    pub fn new_unchecked(from: usize, to: usize) -> Self {
25        ByteRange(from, to)
26    }
27
28    /// Aligns this byte range to the provided `alignment`.
29    pub fn aligned(&self, alignment: usize) -> Self {
30        let modulo = self.0 % alignment;
31        if modulo == 0 {
32            return *self;
33        }
34        self.offset(alignment - modulo)
35    }
36
37    /// Caps the end address of this byte range to the provided `position`.
38    pub fn cap_end(&self, position: usize) -> Self {
39        ByteRange(self.0, position.min(self.1))
40    }
41
42    /// Caps the size of this byte range to the provided `size`.
43    pub fn cap_size(&self, size: usize) -> Self {
44        if self.len() < size {
45            return *self;
46        }
47        ByteRange(self.0, self.0 + size)
48    }
49
50    /// Offsets this byte range by a provided unsigned `offset`.
51    pub fn offset(&self, offset: usize) -> Self {
52        ByteRange(self.0 + offset, self.1 + offset)
53    }
54
55    /// Offsets this byte range by a provided signed offset.
56    pub fn offset_signed(&self, offset: isize) -> Self {
57        ByteRange(
58            ((self.0 as isize).wrapping_add(offset)) as usize,
59            ((self.1 as isize).wrapping_add(offset)) as usize,
60        )
61    }
62
63    /// Returns length of this byte range.
64    pub fn len(&self) -> usize {
65        self.1 - self.0
66    }
67
68    /// Returns true if this byte range is zero-sized.
69    pub fn is_empty(&self) -> bool {
70        self.0 == self.1
71    }
72
73    /// Returns `true` if this byte range contains another byte range `other`.
74    pub fn contains(&self, other: Self) -> bool {
75        self.0 <= other.0 && other.1 <= self.1
76    }
77
78    /// Returns two byte ranges that remain when another `other` range is
79    /// removed from this one.
80    ///
81    /// It is possible for either or both of the returned byte ranges to have a
82    /// length of 0 if `other` is aligned with either the upper or lower bound
83    /// of this range, or if it is equal to this range.
84    pub fn difference_unchecked(&self, other: Self) -> (Self, Self) {
85        (ByteRange(self.0, other.0), ByteRange(other.1, self.1))
86    }
87
88    /// Merges this byte range with `other` and returns a byte range that
89    /// contains both.
90    pub fn merge_unchecked(&self, other: Self) -> Self {
91        ByteRange(self.0.min(other.0), self.1.max(other.1))
92    }
93
94    /// Merges another `other` byte range into this one, resulting in a byte
95    /// range that contains both.
96    pub fn merge_in_unchecked(&mut self, other: Self) {
97        self.0 = self.0.min(other.0);
98        self.1 = self.1.max(other.1);
99    }
100}
101
102impl Display for ByteRange {
103    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104        write!(f, "[{:x}, {:x})", self.0, self.1)
105    }
106}
107
108#[cfg(test)]
109mod test {
110    use super::*;
111
112    #[test]
113    fn byterange_merging_works() {
114        let a = ByteRange::new_unchecked(0, 10);
115        let b = ByteRange::new_unchecked(10, 20);
116
117        let added_seq = a.merge_unchecked(b);
118        assert_eq!(added_seq.0, 0);
119        assert_eq!(added_seq.1, 20);
120
121        let added_seq_rev = b.merge_unchecked(a);
122        assert_eq!(added_seq_rev.0, 0);
123        assert_eq!(added_seq_rev.1, 20);
124    }
125
126    #[test]
127    fn byterange_difference_works() {
128        let larger = ByteRange::new_unchecked(0, 500);
129
130        let left_aligned = ByteRange::new_unchecked(0, 10);
131        let test_left = larger.difference_unchecked(left_aligned);
132        assert_eq!(test_left.0 .0, 0);
133        assert_eq!(test_left.0 .1, 0);
134        assert_eq!(test_left.1 .0, 10);
135        assert_eq!(test_left.1 .1, 500);
136
137        let contained = ByteRange::new_unchecked(300, 400);
138        let test_contained = larger.difference_unchecked(contained);
139        assert_eq!(test_contained.0 .0, 0);
140        assert_eq!(test_contained.0 .1, 300);
141        assert_eq!(test_contained.1 .0, 400);
142        assert_eq!(test_contained.1 .1, 500);
143
144        let right_aligned = ByteRange::new_unchecked(450, 500);
145        let test_right = larger.difference_unchecked(right_aligned);
146        assert_eq!(test_right.0 .0, 0);
147        assert_eq!(test_right.0 .1, 450);
148        assert_eq!(test_right.1 .0, 500);
149        assert_eq!(test_right.1 .1, 500);
150    }
151}