free_ranges/
lib.rs

1use std::cmp::{self, Ordering};
2use std::collections::btree_set::{self, Iter};
3use std::collections::BTreeSet;
4use std::fmt;
5
6#[derive(Debug, Clone, Default)]
7pub struct FreeRanges {
8    free_list: BTreeSet<Range>,
9}
10
11impl FreeRanges {
12    /// Starts empty with no ranges free
13    #[inline]
14    pub fn new() -> Self {
15        Default::default()
16    }
17
18    /// Initializes FreeRanges with 0...usize::MAX already free
19    #[inline]
20    pub fn with_all_free() -> FreeRanges {
21        FreeRanges::with_initial_range(Range {
22            min: 0,
23            max: std::usize::MAX,
24        })
25    }
26
27    /// Initializes FreeRanges with the passed `range` already marked as free
28    #[inline]
29    pub fn with_initial_range(range: Range) -> FreeRanges {
30        let mut ranges = FreeRanges::new();
31        ranges.free_list.insert(range);
32        ranges
33    }
34
35    /// Iterator over all of the contiguous free ranges
36    #[inline]
37    pub fn free_ranges(&self) -> Iter<Range> {
38        self.free_list.iter()
39    }
40
41    /// Iterator over all of the ranges starting at a specific index.
42    /// It will include the first range that contains the index if it
43    /// exists.
44    #[inline]
45    pub fn free_ranges_after(&self, start: usize) -> btree_set::Range<Range> {
46        self.free_list.range(Range::id(start)..)
47    }
48
49    /// Iterator over all of the ranges ending at a specific index.
50    /// It will include the last range that contains the index if it
51    /// exists.
52    #[inline]
53    pub fn free_ranges_before(&self, end: usize) -> btree_set::Range<Range> {
54        use std::collections::Bound;
55        self.free_list
56            .range((Bound::Unbounded, Bound::Included(Range::id(end))))
57    }
58
59    /// Marks a specific index as free
60    #[inline]
61    pub fn set_free(&mut self, index: usize) -> bool {
62        if self.free_list.contains(&Range::id(index)) {
63            return false;
64        }
65
66        let range = Range::id(index);
67        self.do_set_free(range);
68
69        true
70    }
71
72    #[inline]
73    pub fn set_range_free(&mut self, range: Range) -> bool {
74        let front_check = self.free_list.get(&Range::id(range.min)).cloned();
75        let back_check = self.free_list.get(&Range::id(range.max)).cloned();
76
77        match (front_check, back_check) {
78            (Some(front_check), Some(back_check)) => {
79                if front_check == back_check {
80                    return false;
81                }
82            }
83            _ => (),
84        }
85
86        self.do_set_free(range);
87
88        true
89    }
90
91    fn do_set_free(&mut self, range: Range) {
92        let range_front = if range.min > 0 {
93            range.push_front()
94        } else {
95            range
96        };
97        let range_back = range.push_back();
98        let combine_front = self.free_list.get(&range_front).cloned();
99        let combine_back = self.free_list.get(&range_back).cloned();
100
101        match (combine_front, combine_back) {
102            (Some(front_range), Some(back_range)) => {
103                let combined = front_range.merge(range).merge(back_range);
104
105                self.free_list.remove(&front_range);
106                self.free_list.remove(&back_range);
107                self.free_list.insert(combined);
108            }
109            (Some(front_range), None) => {
110                let combined = front_range.merge(range);
111
112                self.free_list.remove(&front_range);
113                self.free_list.insert(combined);
114            }
115            (None, Some(back_range)) => {
116                let combined = back_range.merge(range);
117
118                self.free_list.remove(&back_range);
119                self.free_list.insert(combined);
120            }
121            (None, None) => {
122                self.free_list.insert(range);
123            }
124        }
125    }
126
127    /// Marks a free index as used. Returns false if the index was not free
128    #[inline]
129    pub fn set_used(&mut self, index: usize) -> bool {
130        let range = Range::id(index);
131
132        if let Some(&intersecting) = self.free_list.get(&range) {
133            self.free_list.remove(&intersecting);
134            let (left, right) = intersecting.split(index);
135            if !left.empty() {
136                self.free_list.insert(left);
137            }
138            if !right.empty() {
139                self.free_list.insert(right);
140            }
141            true
142        } else {
143            false
144        }
145    }
146
147    /// Returns the first free value if one exists
148    #[inline]
149    pub fn first(&self) -> Option<usize> {
150        self.free_list.iter().nth(0).map(|r| r.min)
151    }
152
153    /// Marks the first index in the free list as used and returns it
154    #[inline]
155    pub fn set_first_used(&mut self) -> Option<usize> {
156        if let Some(&first) = self.free_list.iter().nth(0) {
157            self.free_list.remove(&first);
158            let range = first.pop_front();
159            if !range.empty() {
160                self.free_list.insert(range);
161            }
162            return Some(first.min);
163        }
164
165        None
166    }
167
168    /// Returns the first free value if one exists
169    #[inline]
170    pub fn last(&self) -> Option<usize> {
171        self.free_list.iter().rev().nth(0).map(|r| r.max)
172    }
173
174    /// Marks the first index in the free list as used and returns it
175    #[inline]
176    pub fn set_last_used(&mut self) -> Option<usize> {
177        if let Some(&last) = self.free_list.iter().rev().nth(0) {
178            self.free_list.remove(&last);
179            if last.max != 0 {
180                let range = last.pop_back();
181                if !range.empty() {
182                    self.free_list.insert(range);
183                }
184            }
185            return Some(last.max);
186        }
187
188        None
189    }
190
191    #[inline]
192    pub fn remove_last_contiguous(&mut self) {
193        if let Some(last) = self.last() {
194            self.free_list.remove(&Range::id(last));
195        }
196    }
197
198    #[inline]
199    pub fn is_free(&self, index: usize) -> bool {
200        let range = Range::id(index);
201        self.free_list.get(&range).is_some()
202    }
203
204    #[inline]
205    pub fn clear(&mut self) {
206        self.free_list.clear();
207    }
208}
209
210const EMPTY_RANGE: Range = Range { min: 1, max: 0 };
211
212#[derive(Copy, Clone)]
213pub struct Range {
214    pub min: usize,
215    pub max: usize,
216}
217
218impl fmt::Debug for Range {
219    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
220        write!(fmt, "({}...{})", self.min, self.max)
221    }
222}
223
224impl Range {
225    #[inline]
226    pub fn id(id: usize) -> Self {
227        Range { min: id, max: id }
228    }
229
230    #[inline]
231    pub fn empty(self) -> bool {
232        self.min > self.max
233    }
234
235    #[inline]
236    pub fn push_front(mut self) -> Self {
237        self.min -= 1;
238        self
239    }
240
241    #[inline]
242    pub fn push_back(mut self) -> Self {
243        self.max += 1;
244        self
245    }
246
247    #[inline]
248    pub fn pop_front(mut self) -> Self {
249        self.min += 1;
250        self
251    }
252
253    #[inline]
254    pub fn pop_back(mut self) -> Self {
255        self.max -= 1;
256        self
257    }
258
259    #[inline]
260    pub fn merge(self, other: Self) -> Self {
261        Range {
262            min: cmp::min(self.min, other.min),
263            max: cmp::max(self.max, other.max),
264        }
265    }
266
267    #[inline]
268    pub fn contains(&self, value: usize) -> bool {
269        value >= self.min && value <= self.max
270    }
271
272    #[inline]
273    pub fn split(self, middle: usize) -> (Range, Range) {
274        if middle == 0 {
275            return (EMPTY_RANGE, self.pop_front());
276        }
277
278        let left = Range {
279            min: self.min,
280            max: middle - 1,
281        };
282        let right = Range {
283            min: middle + 1,
284            max: self.max,
285        };
286        (left, right)
287    }
288}
289
290impl PartialEq for Range {
291    #[inline]
292    fn eq(&self, other: &Self) -> bool {
293        self.cmp(other) == Ordering::Equal
294    }
295}
296
297impl Eq for Range {}
298
299impl PartialOrd for Range {
300    #[inline]
301    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
302        Some(self.cmp(other))
303    }
304}
305
306impl Ord for Range {
307    #[inline]
308    fn cmp(&self, other: &Self) -> Ordering {
309        if self.contains(other.min) || self.contains(other.max) || other.contains(self.min)
310            || other.contains(self.max)
311        {
312            return Ordering::Equal;
313        }
314
315        self.min.cmp(&other.min)
316    }
317}