rustc_data_structures/
flat_map_in_place.rs

1use std::ptr;
2
3use smallvec::{Array, SmallVec};
4use thin_vec::ThinVec;
5
6pub trait FlatMapInPlace<T>: Sized {
7    fn flat_map_in_place<F, I>(&mut self, f: F)
8    where
9        F: FnMut(T) -> I,
10        I: IntoIterator<Item = T>;
11}
12
13// The implementation of this method is syntactically identical for all the
14// different vector types.
15macro_rules! flat_map_in_place {
16    () => {
17        fn flat_map_in_place<F, I>(&mut self, mut f: F)
18        where
19            F: FnMut(T) -> I,
20            I: IntoIterator<Item = T>,
21        {
22            let mut read_i = 0;
23            let mut write_i = 0;
24            unsafe {
25                let mut old_len = self.len();
26                self.set_len(0); // make sure we just leak elements in case of panic
27
28                while read_i < old_len {
29                    // move the read_i'th item out of the vector and map it
30                    // to an iterator
31                    let e = ptr::read(self.as_ptr().add(read_i));
32                    let iter = f(e).into_iter();
33                    read_i += 1;
34
35                    for e in iter {
36                        if write_i < read_i {
37                            ptr::write(self.as_mut_ptr().add(write_i), e);
38                            write_i += 1;
39                        } else {
40                            // If this is reached we ran out of space
41                            // in the middle of the vector.
42                            // However, the vector is in a valid state here,
43                            // so we just do a somewhat inefficient insert.
44                            self.set_len(old_len);
45                            self.insert(write_i, e);
46
47                            old_len = self.len();
48                            self.set_len(0);
49
50                            read_i += 1;
51                            write_i += 1;
52                        }
53                    }
54                }
55
56                // write_i tracks the number of actually written new items.
57                self.set_len(write_i);
58            }
59        }
60    };
61}
62
63impl<T> FlatMapInPlace<T> for Vec<T> {
64    flat_map_in_place!();
65}
66
67impl<T, A: Array<Item = T>> FlatMapInPlace<T> for SmallVec<A> {
68    flat_map_in_place!();
69}
70
71impl<T> FlatMapInPlace<T> for ThinVec<T> {
72    flat_map_in_place!();
73}