bisection/
lib.rs

1pub use crate::bisect_right as bisect;
2pub use crate::insort_right as insort;
3
4use std::cmp::Ordering;
5use std::ops::{Bound::*, RangeBounds};
6
7// TODO: Doctest examples
8
9/// Insert `x` in `a[within]`, keeping it sorted assuming `a` is sorted.
10///
11/// If `a` contains `x`, insert it just *after* the *rightmost* occurence of `x`.
12///
13/// # Panics
14///
15/// Panics if `within` is out of bounds of `a`.
16pub fn insort_right_slice<T, I>(a: &mut Vec<T>, x: T, within: I)
17where
18    I: RangeBounds<usize>,
19    T: Ord,
20{
21    insort_right_slice_by(a, x, within, T::cmp);
22}
23
24/// Insert `x` in `a`, keeping it sorted assuming `a` is sorted.
25/// If `a` contains `x`, insert it just *after* the *rightmost* occurence of `x`.
26pub fn insort_right<T>(a: &mut Vec<T>, x: T)
27where
28    T: Ord,
29{
30    insort_right_by(a, x, T::cmp);
31}
32
33/// Insert `x` in `a`, keeping it sorted, assuming `a` is sorted, according to a comparator
34/// function.
35///
36/// The comparator function should implement an order consistent with the sort order of the
37/// underlying slice.
38///
39/// If `a` contains `x`, insert it just *after* the *rightmost* occurence of `x`.
40pub fn insort_right_by<T, F>(a: &mut Vec<T>, x: T, f: F)
41where
42    T: Ord,
43    F: FnMut(&T, &T) -> Ordering,
44{
45    insort_right_slice_by(a, x, .., f);
46}
47
48/// Insert x in `a[within]`, keeping it sorted, assuming `a` is sorted, according to a comparator
49/// function.
50///
51/// The comparator function should implement an order consistent with the sort order of the
52/// underlying slice.
53///
54/// If `a` contains `x`, insert it just *after* the *rightmost* occurence of `x`.
55///
56/// # Panics
57///
58/// Panics if `within` is out of bounds of `a`.
59pub fn insort_right_slice_by<T, I, F>(a: &mut Vec<T>, x: T, within: I, mut f: F)
60where
61    I: RangeBounds<usize>,
62    F: FnMut(&T, &T) -> Ordering,
63{
64    let lo = bisect_right_slice_by(a, within, |p| f(&x, p));
65    a.insert(lo, x);
66}
67
68/// Return the index where `x` should be inserted in `a[within]`, assuming `a`
69/// is sorted.
70///
71/// The return value `i` is such that all `e` in `a[..i]` have `e <= x`, and
72/// all `e` in `a[i..]` have `e > x`.
73/// - If `a` contains `x`, `a.insert(i, x)` will insert just *after* the
74///   *rightmost* `x`.
75///
76/// # Panics
77///
78/// Panics if `within` is out of bounds of `a`.
79pub fn bisect_right_slice<T, I>(a: &[T], x: &T, within: I) -> usize
80where
81    I: RangeBounds<usize>,
82    T: Ord,
83{
84    bisect_right_slice_by(a, within, |p| x.cmp(p))
85}
86
87/// Return the index where `x` should be inserted in `a`, assuming `a` is sorted.
88///
89/// The return value `i` is such that all `e` in `a[..i]` have `e <= x`, and
90/// all `e` in `a[i..]` have `e > x`.
91/// - If `a` contains `x`, `a.insert(i, x)` will insert just *after* the
92///   *rightmost* occurence of `x`.
93pub fn bisect_right<T>(a: &[T], x: &T) -> usize
94where
95    T: Ord,
96{
97    bisect_right_slice(a, x, ..)
98}
99
100/// Return the index where `x` should be inserted in `a`, assuming `a` is sorted, according to
101/// a comparator function.
102///
103/// The comparator function should implement an order consistent with the sort order of the
104/// underlying slice, returning an order code that indicates whethers its argument is `Less`,
105/// `Equal` or `Greater` that the **desired target**.
106///
107/// The return value `i` is such that all `e` in `a[..i]` have `f(e) == Less | f(e) == Equal`, and
108/// all `e` in `a[i..]` have `f(e) == Greater`.
109/// - If `a` contains `x`, `a.insert(i, x)` will insert just *after* the
110///   *rightmost* occurence of `x`.
111pub fn bisect_right_by<T, F>(a: &[T], f: F) -> usize
112where
113    F: FnMut(&T) -> Ordering,
114{
115    bisect_right_slice_by(a, .., f)
116}
117
118/// Return the index where a value should be inserted in `a[within]`, assuming it sorted,
119/// according to a comparator function.
120///
121/// The comparator function should implement an order consistent with the sort order of the
122/// underlying slice, returning an order code that indicates whethers its argument is `Less`,
123/// `Equal` or `Greater` that the **desired target**.
124///
125/// The return value `i` is such that all `e` in `a[..i]` have `f(e) == Less | f(e) == Equal`, and
126/// all `e` in `a[i..]` have `f(e) == Greater`.
127/// - If `a` contains `x`, `a.insert(i, x)` will insert just *after* the
128///   *rightmost* occurence of `x`.
129///
130/// # Panics
131///
132/// Panics if `within` is out of bounds of `a`.
133pub fn bisect_right_slice_by<T, I, F>(a: &[T], within: I, mut f: F) -> usize
134where
135    I: RangeBounds<usize>,
136    F: FnMut(&T) -> Ordering,
137{
138    let (mut lo, mut hi) = bounds_to_indices(a, within);
139    while lo < hi {
140        let mid = (lo + hi) / 2;
141        if f(&a[mid]) == Ordering::Less {
142            hi = mid;
143        } else {
144            lo = mid + 1;
145        }
146    }
147    lo
148}
149
150/// Insert `x` in `a[within]`, keeping it sorted assuming `a` is sorted.
151///
152/// If `a` contains `x`, insert it just *before* the *leftmost* occurence of `x`.
153///
154/// # Panics
155///
156/// Panics if `within` is out of bounds of `a`.
157pub fn insort_left_slice<T, I>(a: &mut Vec<T>, x: T, within: I)
158where
159    I: RangeBounds<usize>,
160    T: Ord,
161{
162    insort_left_slice_by(a, x, within, T::cmp);
163}
164
165/// Insert `x` in `a`, keeping it sorted assuming `a` is sorted.
166///
167/// If `a` contains `x`, insert it just *before* the *leftmost* occurence of `x`.
168pub fn insort_left<T>(a: &mut Vec<T>, x: T)
169where
170    T: Ord,
171{
172    insort_left_by(a, x, T::cmp);
173}
174
175/// Insert `x` in `a`, keeping it sorted, assuming `a` is sorted, according to a comparator
176/// function.
177///
178/// The comparator function should implement an order consistent with the sort order of the
179/// underlying slice.
180///
181/// If `a` contains `x`, insert it just *before* the *leftmost* occurence of `x`.
182pub fn insort_left_by<T, F>(a: &mut Vec<T>, x: T, f: F)
183where
184    T: Ord,
185    F: FnMut(&T, &T) -> Ordering,
186{
187    insort_left_slice_by(a, x, .., f);
188}
189
190/// Insert x in `a[within]`, keeping it sorted, assuming `a` is sorted, according to a comparator
191/// function.
192///
193/// The comparator function should implement an order consistent with the sort order of the
194/// underlying slice.
195///
196/// If `a` contains `x`, insert it just *before* the *leftmost* occurence of `x`.
197///
198/// # Panics
199///
200/// Panics if `within` is out of bounds of `a`.
201pub fn insort_left_slice_by<T, I, F>(a: &mut Vec<T>, x: T, within: I, mut f: F)
202where
203    I: RangeBounds<usize>,
204    F: FnMut(&T, &T) -> Ordering,
205{
206    let lo = bisect_right_slice_by(a, within, |p| f(&x, p));
207    a.insert(lo, x);
208}
209
210/// Return the index where `x` should be inserted in `a[within]`, assuming `a`
211/// is sorted.
212///
213/// The return value `i` is such that all `e` in `a[..i]` have `e < x`, and
214/// all `e` in `a[i..]` have `e >= x`.
215/// - If `a` contains `x`, `a.insert(i, x)` will insert just *before* the
216///   *leftmost* `x`.
217///
218/// # Panics
219///
220/// Panics if `within` is out of bounds of `a`.
221pub fn bisect_left_slice<T, I>(a: &[T], x: &T, within: I) -> usize
222where
223    I: RangeBounds<usize>,
224    T: Ord,
225{
226    bisect_left_slice_by(a, within, |p| p.cmp(x))
227}
228
229/// Return the index where `x` should be inserted in `a`, assuming `a` is sorted.
230///
231/// The return value `i` is such that all `e` in `a[..i]` have `e < x`, and
232/// all `e` in `a[i..]` have `e >= x`.
233/// - If `a` contains `x`, `a.insert(i, x)` will insert just *before* the
234///   *leftmost* `x`.
235pub fn bisect_left<T>(a: &[T], x: &T) -> usize
236where
237    T: Ord,
238{
239    bisect_left_slice(a, x, ..)
240}
241
242/// Return the index where a value should be inserted in `a`, assuming `a` is sorted, according to
243/// a comparator function.
244///
245/// The comparator function should implement an order consistent with the sort order of the
246/// underlying slice, returning an order code that indicates whethers its argument is `Less`,
247/// `Equal` or `Greater` that the **desired target**.
248///
249/// The return value `i` is such that all `e` in `a[..i]` have `f(e) == Less`, and
250/// all `e` in `a[i..]` have `f(e) == Greater | f(e) == Equal`
251/// - If `a` contains `x`, `a.insert(i, x)` will insert just *before* the
252///   *leftmost* `x`.
253pub fn bisect_left_by<T, F>(a: &[T], f: F) -> usize
254where
255    F: FnMut(&T) -> Ordering,
256{
257    bisect_left_slice_by(a, .., f)
258}
259
260/// Return the index where a value should be inserted in `a[within]`, assuming it sorted,
261/// according to a comparator function.
262///
263/// The comparator function should implement an order consistent with the sort order of the
264/// underlying slice, returning an order code that indicates whethers its argument is `Less`,
265/// `Equal` or `Greater` that the **desired target**.
266///
267/// The return value `i` is such that all `e` in `a[..i]` have `f(e) == Less`, and
268/// all `e` in `a[i..]` have `f(e) == Greater | f(e) == Equal`
269/// - If `a` contains `x`, `a.insert(i, x)` will insert just *before* the
270///   *leftmost* `x`.
271/// # Panics
272///
273/// Panics if `within` is out of bounds of `a`.
274pub fn bisect_left_slice_by<T, I, F>(a: &[T], within: I, mut f: F) -> usize
275where
276    I: RangeBounds<usize>,
277    F: FnMut(&T) -> Ordering,
278{
279    let (mut lo, mut hi) = bounds_to_indices(a, within);
280    while lo < hi {
281        let mid = (lo + hi) / 2;
282        let cmp = f(&a[mid]);
283        if cmp == Ordering::Less {
284            lo = mid + 1;
285        } else {
286            hi = mid;
287        }
288    }
289    lo
290}
291
292/// Convert bounds to a `(lo, hi)`  pair for indexing into a slice of `a`.
293///
294/// # Panics
295///
296/// Panics if `within` is out of bounds of `a`.
297fn bounds_to_indices<T, I>(a: &[T], within: I) -> (usize, usize)
298where
299    I: RangeBounds<usize>,
300{
301    // TODO: Panics
302    let lo = match within.start_bound() {
303        Unbounded => 0,
304        Included(i) => *i,
305        Excluded(i) => i + 1,
306    };
307
308    let hi = match within.end_bound() {
309        Unbounded => a.len(),
310        Included(i) => i + 1,
311        Excluded(i) => *i,
312    };
313
314    if hi > a.len() {
315        panic!("index out of bounds")
316    }
317
318    (lo, hi)
319}
320
321#[cfg(test)]
322mod tests {
323
324    use super::*;
325    use proptest::prelude::*;
326    use std::collections::HashSet;
327    use std::iter::FromIterator;
328
329    #[derive(Clone, Debug)]
330    struct BisectTest<T: 'static>
331    where
332        T: Ord,
333    {
334        name: &'static str,
335        a: &'static [T],
336        x: T,
337        expected_index: usize,
338    }
339
340    #[derive(Debug, Clone)]
341    enum TestDirection {
342        Left,
343        Right,
344    }
345
346    type TestCollection<T: Ord + Clone> = &'static [BisectTest<T>];
347
348    macro_rules! t {
349        ($name:ident, $a:expr, $x:expr, $expected_index:expr) => {
350            BisectTest {
351                name: stringify!($name),
352                a: $a,
353                x: $x,
354                expected_index: $expected_index,
355            }
356        };
357    }
358
359    const RIGHT_INT_CASES: TestCollection<i32> = &[
360        t!(ints_right_0, &[], 1, 0),
361        t!(ints_right_1, &[1], 0, 0),
362        t!(ints_right_2, &[1], 1, 1),
363        t!(ints_right_3, &[1], 2, 1),
364        t!(ints_right_4, &[1, 1], 0, 0),
365        t!(ints_right_5, &[1, 1], 1, 2),
366        t!(ints_right_6, &[1, 1], 2, 2),
367        t!(ints_right_7, &[1, 1, 1], 0, 0),
368        t!(ints_right_8, &[1, 1, 1], 1, 3),
369        t!(ints_right_9, &[1, 1, 1], 2, 3),
370        t!(ints_right_10, &[1, 1, 1, 1], 0, 0),
371        t!(ints_right_11, &[1, 1, 1, 1], 1, 4),
372        t!(ints_right_12, &[1, 1, 1, 1], 2, 4),
373        t!(ints_right_13, &[1, 2], 0, 0),
374        t!(ints_right_14, &[1, 2], 1, 1),
375        t!(ints_right_15, &[1, 2], 2, 2),
376        t!(ints_right_16, &[1, 2], 3, 2),
377        t!(ints_right_17, &[1, 1, 2, 2], 0, 0),
378        t!(ints_right_18, &[1, 1, 2, 2], 1, 2),
379        t!(ints_right_19, &[1, 1, 2, 2], 2, 4),
380        t!(ints_right_20, &[1, 1, 2, 2], 3, 4),
381        t!(ints_right_21, &[1, 2, 3], 0, 0),
382        t!(ints_right_22, &[1, 2, 3], 1, 1),
383        t!(ints_right_23, &[1, 2, 3], 2, 2),
384        t!(ints_right_24, &[1, 2, 3], 3, 3),
385        t!(ints_right_25, &[1, 2, 3], 4, 3),
386        t!(ints_right_26, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
387        t!(ints_right_27, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1),
388        t!(ints_right_28, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3),
389        t!(ints_right_29, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6),
390        t!(ints_right_30, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10),
391        t!(ints_right_31, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
392    ];
393
394    const LEFT_INT_CASES: TestCollection<i32> = &[
395        t!(ints_left_0, &[], 1, 0),
396        t!(ints_left_1, &[1], 0, 0),
397        t!(ints_left_2, &[1], 1, 0),
398        t!(ints_left_3, &[1], 2, 1),
399        t!(ints_left_4, &[1, 1], 0, 0),
400        t!(ints_left_5, &[1, 1], 1, 0),
401        t!(ints_left_6, &[1, 1], 2, 2),
402        t!(ints_left_7, &[1, 1, 1], 0, 0),
403        t!(ints_left_8, &[1, 1, 1], 1, 0),
404        t!(ints_left_9, &[1, 1, 1], 2, 3),
405        t!(ints_left_10, &[1, 1, 1, 1], 0, 0),
406        t!(ints_left_11, &[1, 1, 1, 1], 1, 0),
407        t!(ints_left_12, &[1, 1, 1, 1], 2, 4),
408        t!(ints_left_13, &[1, 2], 0, 0),
409        t!(ints_left_14, &[1, 2], 1, 0),
410        t!(ints_left_15, &[1, 2], 2, 1),
411        t!(ints_left_16, &[1, 2], 3, 2),
412        t!(ints_left_17, &[1, 1, 2, 2], 0, 0),
413        t!(ints_left_18, &[1, 1, 2, 2], 1, 0),
414        t!(ints_left_19, &[1, 1, 2, 2], 2, 2),
415        t!(ints_left_20, &[1, 1, 2, 2], 3, 4),
416        t!(ints_left_21, &[1, 2, 3], 0, 0),
417        t!(ints_left_22, &[1, 2, 3], 1, 0),
418        t!(ints_left_23, &[1, 2, 3], 2, 1),
419        t!(ints_left_24, &[1, 2, 3], 3, 2),
420        t!(ints_left_25, &[1, 2, 3], 4, 3),
421        t!(ints_left_26, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
422        t!(ints_left_27, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0),
423        t!(ints_left_28, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1),
424        t!(ints_left_29, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3),
425        t!(ints_left_30, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6),
426        t!(ints_left_31, &[1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
427    ];
428
429    #[test]
430    fn bisect_right_precomputed() {
431        run_bisect_tests(TestDirection::Right, RIGHT_INT_CASES);
432    }
433
434    #[test]
435    fn bisect_left_precomputed() {
436        run_bisect_tests(TestDirection::Left, LEFT_INT_CASES);
437    }
438
439    #[test]
440    fn bisect_right_slice_precomputed() {
441        run_bisect_slice_tests(TestDirection::Right, RIGHT_INT_CASES);
442    }
443
444    #[test]
445    fn bisect_left_slice_precomputed() {
446        run_bisect_slice_tests(TestDirection::Left, LEFT_INT_CASES);
447    }
448
449    #[test]
450    #[should_panic]
451    fn right_slice_index_out_of_bounds() {
452        let a: Vec<u32> = (0..10).collect();
453        // 10 does not fit within 5..10 so the search goes into the out of bounds range
454        bisect_right_slice(&a, &10, 5..15);
455    }
456
457    #[test]
458    #[should_panic]
459    fn left_slice_index_out_of_bounds() {
460        let a: Vec<u32> = (0..10).collect();
461        // 10 does not fit within 5..10 so the search goes into the out of bounds range
462        bisect_left_slice(&a, &10, 5..15);
463    }
464
465    #[test]
466    #[should_panic]
467    fn right_slice_index_out_of_bounds_when_not_searched() {
468        let a: Vec<u32> = (0..10).collect();
469        // 5 fits within 0..10 bounds so the search *doesnt* actually index into the out of bounds
470        bisect_right_slice(&a, &5, ..15);
471    }
472
473    #[test]
474    #[should_panic]
475    fn left_slice_index_out_of_bounds_when_not_searched() {
476        let a: Vec<u32> = (0..10).collect();
477        // 5 fits within 0..10 bounds so the search *doesnt* actually index into the out of bounds
478        bisect_left_slice(&a, &5, ..15);
479    }
480
481    fn run_bisect_tests<T: Clone + Ord>(direction: TestDirection, test_cases: TestCollection<T>) {
482        let bisect_func = match direction {
483            TestDirection::Left => bisect_left,
484            TestDirection::Right => bisect_right,
485        };
486
487        for test_case in test_cases {
488            let data = test_case.a.to_vec();
489            assert_eq!(test_case.expected_index, bisect_func(&data, &test_case.x));
490        }
491    }
492
493    fn run_bisect_slice_tests<T: Clone + Ord>(
494        direction: TestDirection,
495        test_cases: TestCollection<T>,
496    ) {
497        let bisect_func = match direction {
498            TestDirection::Left => bisect_left_slice,
499            TestDirection::Right => bisect_right_slice,
500        };
501
502        for test_case in test_cases {
503            let data = test_case.a.to_vec();
504            for lo in 0..4 {
505                for hi in 3..8 {
506                    let hi = std::cmp::min(data.len(), hi);
507                    let ip = bisect_func(&data, &test_case.x, lo..hi);
508
509                    match direction {
510                        TestDirection::Left => {
511                            if ip < hi {
512                                assert!(test_case.x <= data[ip]);
513                            }
514
515                            if ip > lo {
516                                assert!(data[ip - 1] < test_case.x)
517                            }
518                        }
519                        TestDirection::Right => {
520                            if ip < hi {
521                                assert!(test_case.x < data[ip]);
522                            }
523
524                            if ip > lo {
525                                assert!(data[ip - 1] <= test_case.x)
526                            }
527                        }
528                    }
529
530                    assert_eq!(
531                        ip,
532                        std::cmp::max(lo, std::cmp::min(hi, test_case.expected_index))
533                    );
534                }
535            }
536        }
537    }
538
539    #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
540    struct Person {
541        name: String,
542        age: u32,
543    }
544
545    fn arb_person() -> impl Strategy<Value = Person> {
546        ("[a-z]*", 1..100_u32).prop_map(|(name, age)| Person { name, age })
547    }
548
549    fn check_index_right_invariant<T, F>(a: &[T], target: &T, index: usize, mut f: F)
550    where
551        F: FnMut(&T, &T) -> Ordering,
552    {
553        // See `bisect_right_by` docs
554        assert!(a[..index].iter().all(|x| match f(x, &target) {
555            Ordering::Less | Ordering::Equal => true,
556            _ => false,
557        }));
558        assert!(a[index..]
559            .iter()
560            .all(|x| f(x, &target) == Ordering::Greater));
561    }
562
563    fn check_index_left_invariant<T, F>(a: &[T], target: &T, index: usize, mut f: F)
564    where
565        F: FnMut(&T, &T) -> Ordering,
566    {
567        // See `bisect_left_by` docs
568        assert!(a[..index].iter().all(|x| f(x, &target) == Ordering::Less));
569        assert!(a[index..].iter().all(|x| match f(x, &target) {
570            Ordering::Greater | Ordering::Equal => true,
571            _ => false,
572        }));
573    }
574
575    proptest! {
576
577        #[test]
578        fn test_bisect_left_index_invariant(
579            mut nums in prop::collection::vec(any::<u32>(), 0..500),
580            num in any::<u32>()
581        ) {
582            nums.sort();
583
584            let i = bisect_left(&nums, &num);
585
586            check_index_left_invariant(&nums, &num, i, u32::cmp);
587        }
588
589        #[test]
590        fn test_bisect_left_by_index_invariant(
591            mut people in prop::collection::vec(arb_person(), 0..500),
592            new_person in arb_person()
593        ) {
594            // Sort by age only
595            let f = |a: &Person, b: &Person| a.age.cmp(&b.age);
596
597            people.sort_by(f);
598
599            let i = bisect_left_by(&people, |p| f(p, &new_person));
600
601            check_index_left_invariant(&people, &new_person, i, f);
602
603            // Sort by name only
604            let f = |a: &Person, b: &Person| a.name.cmp(&b.name);
605
606            people.sort_by(f);
607
608            let i = bisect_left_by(&people, |p| f(p, &new_person));
609
610            check_index_left_invariant(&people, &new_person, i, f);
611        }
612
613        #[test]
614        fn test_bisect_right_index_invariant(
615            mut nums in prop::collection::vec(any::<u32>(), 0..500),
616            num in any::<u32>()
617        ) {
618            nums.sort();
619
620            let i = bisect_right(&nums, &num);
621
622            check_index_right_invariant(&nums, &num, i, u32::cmp)
623        }
624
625        #[test]
626        fn test_bisect_right_by_index_invariant(
627            mut people in prop::collection::vec(arb_person(), 0..500),
628            new_person in arb_person()
629        ) {
630            // Sort by age only
631            let f = |a: &Person, b: &Person| a.age.cmp(&b.age);
632
633            people.sort_by(f);
634
635            let i = bisect_right_by(&people, |p| f(&new_person, p));
636
637            check_index_right_invariant(&people, &new_person, i, f);
638
639
640            // Sort by name only
641            let f = |a: &Person, b: &Person| a.name.cmp(&b.name);
642
643            people.sort_by(f);
644
645            let i = bisect_right_by(&people, |p| f(&new_person, p));
646
647            check_index_right_invariant(&people, &new_person, i, f);
648        }
649
650        #[test]
651        fn test_insort_vs_vec_sort(
652            digits in prop::collection::vec(0..10, 0..500)
653        ) {
654            let left_digits = HashSet::<i32>::from_iter(vec![0, 2, 4, 6, 8]);
655            let mut insorted = vec![];
656
657            for digit in digits {
658                let f = if  left_digits.contains(&digit) {
659                    insort_left
660                } else {
661                    insort_right
662                };
663
664                f(&mut insorted, digit);
665            }
666
667            let vec_sorted = {
668                let mut v = insorted.clone();
669                v.sort();
670                v
671            };
672
673            assert_eq!(vec_sorted, insorted);
674        }
675    }
676}