s2n_quic_core/interval_set/insert.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::interval_set::{Interval, IntervalBound, IntervalSetError};
5use alloc::collections::VecDeque;
6use core::{
7 cmp::{max, min, Ordering},
8 num::NonZeroUsize,
9 ops::Range,
10};
11
12#[inline]
13pub(crate) fn insert<T: IntervalBound + Ord>(
14 ranges: &mut VecDeque<Interval<T>>,
15 mut range: Interval<T>,
16 start_index: usize,
17 limit: Option<NonZeroUsize>,
18) -> Result<usize, IntervalSetError> {
19 // this range is intentionally invalid and will only be
20 // valid if the `scan` method finds a match
21 #[allow(clippy::reversed_empty_ranges)]
22 let replace_range = usize::MAX..0;
23
24 let mut insertion = Insertion { replace_range };
25
26 let iter = ranges.iter().enumerate().skip(start_index);
27
28 if let Some(index) = insertion.scan(iter, &mut range) {
29 return Ok(index);
30 }
31
32 insertion.apply(ranges, range, limit)
33}
34
35/// A structure to keep temporary state for an insertion
36#[derive(Debug)]
37struct Insertion {
38 replace_range: Range<usize>,
39}
40
41impl Insertion {
42 /// Scans over the Intervals and updates the `Insertion` state with the
43 /// applicable interval ranges
44 ///
45 /// Returns `Some(index)` if the `Interval` is already present in the iterator,
46 /// otherwise `None` is returned.
47 #[inline]
48 fn scan<'a, T: 'a + Ord + IntervalBound, I: Iterator<Item = (usize, &'a Interval<T>)>>(
49 &mut self,
50 ranges: I,
51 range_a: &mut Interval<T>,
52 ) -> Option<usize> {
53 use Ordering::*;
54
55 for (slot_index, range_b) in ranges {
56 match (
57 range_a.start.cmp(&range_b.start),
58 range_a.end.cmp(&range_b.end),
59 ) {
60 // the ranges are equal
61 //
62 // range A: |---------|
63 // range B: |---------|
64 //
65 (Equal, Equal) |
66
67 // range A is a subset of range B
68 //
69 // range A: |-----|
70 // range B: |---------|
71 //
72 // do nothing
73 //
74 (Greater, Equal) => return Some(slot_index + 1),
75
76 // range A is a subset of range B
77 //
78 // range A: |-----|
79 // range B: |---------|
80 //
81 // do nothing
82 //
83 (Equal, Less) |
84
85 // range A is a subset of range B
86 //
87 // range A: |----|
88 // range B: |---------|
89 //
90 (Greater, Less) => return Some(slot_index),
91
92 // range A is part of range B.
93 //
94 // Before:
95 //
96 // range A: |--------|
97 // range B: |--------|
98 //
99 // After:
100 //
101 // range A: |-------------|
102 // range B: |
103 //
104 (Greater, Greater) if range_a.should_coalesce(range_b) => {
105 range_a.start = range_b.start;
106 self.set_start(slot_index);
107 let next_slot = slot_index + 1;
108 self.set_end(next_slot);
109 continue;
110 }
111
112 // range A comes later
113 //
114 // range A: |-----|
115 // range B: |----|
116 //
117 (Greater, Greater) => {
118 continue;
119 }
120
121 // range A contains range B, spilling over into the next slot
122 //
123 // range A: |---------|
124 // range B: |---|
125 //
126 // mark B as obsolete
127 //
128 (Equal, Greater) |
129
130 // range A contains range B, spilling over into the next slot
131 //
132 // range A: |---------|
133 // range B: |---|
134 //
135 // mark B as obsolete
136 //
137 (Less, Greater) => {
138 self.set_start(slot_index);
139 let next_slot = slot_index + 1;
140 self.set_end(next_slot);
141 continue;
142 }
143
144 // range A ends with range B
145 //
146 // range A: |---------|
147 // range B: |---|
148 //
149 // mark B as obsolete and return
150 //
151 (Less, Equal) => {
152 self.set_start(slot_index);
153 let next_slot = slot_index + 1;
154 self.set_end(next_slot);
155 break;
156 }
157
158 // range A overlaps part of range B
159 //
160 // Before:
161 //
162 // range A: |--------|
163 // range B: |--------|
164 //
165 // After:
166 //
167 // range A: |-------------|
168 // range B: |
169 //
170 (Less, Less) if range_b.should_coalesce(range_a) => {
171 range_a.end = range_b.end;
172 self.set_start(slot_index);
173 let next_slot = slot_index + 1;
174 self.set_end(next_slot);
175 break;
176 }
177
178 // range A comes before range B
179 //
180 // range A: |---|
181 // range B: |--------|
182 //
183 // returns; no more searching needed
184 //
185 (Less, Less) => {
186 self.set_start(slot_index);
187 self.set_end(slot_index);
188 break;
189 }
190 }
191 }
192
193 None
194 }
195
196 /// Applies the `Insertion` to the given set of `Interval`s.
197 #[inline]
198 fn apply<T>(
199 self,
200 ranges: &mut VecDeque<Interval<T>>,
201 range: Interval<T>,
202 limit: Option<NonZeroUsize>,
203 ) -> Result<usize, IntervalSetError> {
204 let replace_range = self.replace_range;
205 let prev_len = ranges.len();
206
207 let ensure_can_insert = || {
208 let under_limit = if let Some(limit) = limit {
209 limit.get() > prev_len
210 } else {
211 true
212 };
213
214 if under_limit {
215 Ok(())
216 } else {
217 Err(IntervalSetError::LimitExceeded)
218 }
219 };
220
221 let index = replace_range.start;
222 let replace_count = if let Some(count) = replace_range.end.checked_sub(index) {
223 count
224 } else {
225 ensure_can_insert()?;
226
227 // add it to the end
228 ranges.push_back(range);
229 return Ok(prev_len);
230 };
231
232 match replace_count {
233 0 => {
234 ensure_can_insert()?;
235 ranges.insert(index, range);
236 }
237 1 => {
238 ranges[index] = range;
239 }
240 2 => {
241 ranges[index] = range;
242 ranges.remove(index + 1);
243 }
244 _ => {
245 ranges[index] = range;
246 ranges.drain(index + 1..replace_range.end);
247 }
248 };
249
250 Ok(index)
251 }
252
253 #[inline]
254 fn set_start(&mut self, start: usize) {
255 self.replace_range.start = min(self.replace_range.start, start);
256 }
257
258 #[inline]
259 fn set_end(&mut self, end: usize) {
260 self.replace_range.end = max(self.replace_range.end, end);
261 }
262}