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}