Skip to main content

differential_dataflow/trace/cursor/
cursor_list.rs

1//! A generic cursor implementation merging multiple cursors.
2
3use super::Cursor;
4
5/// Provides a cursor interface over a list of cursors.
6///
7/// The `CursorList` tracks the indices of cursors with the minimum key, and the the indices of cursors with
8/// the minimum key and minimum value. It performs no clever management of these sets otherwise.
9#[derive(Debug)]
10pub struct CursorList<C> {
11    cursors: Vec<C>,
12    min_key: Vec<usize>,
13    min_val: Vec<usize>,
14}
15
16impl<C: Cursor> CursorList<C> {
17    /// Creates a new cursor list from pre-existing cursors.
18    pub fn new(cursors: Vec<C>, storage: &[C::Storage]) -> Self  {
19        let mut result = CursorList {
20            cursors,
21            min_key: Vec::new(),
22            min_val: Vec::new(),
23        };
24
25        result.minimize_keys(storage);
26        result
27    }
28
29    /// Initialize min_key with the indices of cursors with the minimum key.
30    ///
31    /// This method scans the current keys of each cursor, and tracks the indices
32    /// of cursors whose key equals the minimum valid key seen so far. As it goes,
33    /// if it observes an improved key it clears the current list, updates the
34    /// minimum key, and continues.
35    ///
36    /// Once finished, it invokes `minimize_vals()` to ensure the value cursor is
37    /// in a consistent state as well.
38    fn minimize_keys(&mut self, storage: &[C::Storage]) {
39
40        self.min_key.clear();
41
42        // We'll visit each non-`None` key, maintaining the indexes of the least keys in `self.min_key`.
43        // An explicit min-tracking loop rather than `flat_map`: the adapter's inner `next` fails to
44        // inline in hot callers (e.g. reduce's per-key replay) and surfaces as a hot `FlattenCompat::next`.
45        let mut min_key = None;
46        for (idx, cursor) in self.cursors.iter().enumerate() {
47            if let Some(key) = cursor.get_key(&storage[idx]) {
48                match min_key {
49                    None => {
50                        self.min_key.push(idx);
51                        min_key = Some(key);
52                    }
53                    Some(min) => match key.cmp(&min) {
54                        std::cmp::Ordering::Less => {
55                            self.min_key.clear();
56                            self.min_key.push(idx);
57                            min_key = Some(key);
58                        }
59                        std::cmp::Ordering::Equal => {
60                            self.min_key.push(idx);
61                        }
62                        std::cmp::Ordering::Greater => { }
63                    }
64                }
65            }
66        }
67
68        self.minimize_vals(storage);
69    }
70
71    /// Initialize min_val with the indices of minimum key cursors with the minimum value.
72    ///
73    /// This method scans the current values of cursor with minimum keys, and tracks the
74    /// indices of cursors whose value equals the minimum valid value seen so far. As it
75    /// goes, if it observes an improved value it clears the current list, updates the minimum
76    /// value, and continues.
77    fn minimize_vals(&mut self, storage: &[C::Storage]) {
78
79        self.min_val.clear();
80
81        // We'll visit each non-`None` value, maintaining the indexes of the least values in `self.min_val`.
82        // Explicit loop rather than `flat_map`, for the inlining reason noted in `minimize_keys`.
83        let mut min_val = None;
84        for idx in self.min_key.iter().cloned() {
85            if let Some(val) = self.cursors[idx].get_val(&storage[idx]) {
86                match min_val {
87                    None => {
88                        self.min_val.push(idx);
89                        min_val = Some(val);
90                    }
91                    Some(min) => match val.cmp(&min) {
92                        std::cmp::Ordering::Less => {
93                            self.min_val.clear();
94                            self.min_val.push(idx);
95                            min_val = Some(val);
96                        }
97                        std::cmp::Ordering::Equal => {
98                            self.min_val.push(idx);
99                        }
100                        std::cmp::Ordering::Greater => { }
101                    }
102                }
103            }
104        }
105    }
106}
107
108impl<C: Cursor> Cursor for CursorList<C> {
109
110    type Storage = Vec<C::Storage>;
111
112    type Key<'a> = C::Key<'a>;
113    type ValOwn = C::ValOwn;
114    type Val<'a> = C::Val<'a>;
115    type Time = C::Time;
116    type TimeGat<'a> = C::TimeGat<'a>;
117    type Diff = C::Diff;
118    type DiffGat<'a> = C::DiffGat<'a>;
119    type KeyContainer = C::KeyContainer;
120    type ValContainer = C::ValContainer;
121    type TimeContainer = C::TimeContainer;
122    type DiffContainer = C::DiffContainer;
123
124    // validation methods
125    #[inline]
126    fn key_valid(&self, _storage: &Vec<C::Storage>) -> bool { !self.min_key.is_empty() }
127    #[inline]
128    fn val_valid(&self, _storage: &Vec<C::Storage>) -> bool { !self.min_val.is_empty() }
129
130    // accessors
131    #[inline]
132    fn key<'a>(&self, storage: &'a Vec<C::Storage>) -> Self::Key<'a> {
133        debug_assert!(self.key_valid(storage));
134        debug_assert!(self.cursors[self.min_key[0]].key_valid(&storage[self.min_key[0]]));
135        self.cursors[self.min_key[0]].key(&storage[self.min_key[0]])
136    }
137    #[inline]
138    fn val<'a>(&self, storage: &'a Vec<C::Storage>) -> Self::Val<'a> {
139        debug_assert!(self.key_valid(storage));
140        debug_assert!(self.val_valid(storage));
141        debug_assert!(self.cursors[self.min_val[0]].val_valid(&storage[self.min_val[0]]));
142        self.cursors[self.min_val[0]].val(&storage[self.min_val[0]])
143    }
144    #[inline]
145    fn get_key<'a>(&self, storage: &'a Vec<C::Storage>) -> Option<Self::Key<'a>> {
146        self.min_key.get(0).map(|idx| self.cursors[*idx].key(&storage[*idx]))
147    }
148    #[inline]
149    fn get_val<'a>(&self, storage: &'a Vec<C::Storage>) -> Option<Self::Val<'a>> {
150        self.min_val.get(0).map(|idx| self.cursors[*idx].val(&storage[*idx]))
151    }
152
153    #[inline]
154    fn map_times<L: FnMut(Self::TimeGat<'_>, Self::DiffGat<'_>)>(&mut self, storage: &Vec<C::Storage>, mut logic: L) {
155        for &index in self.min_val.iter() {
156            self.cursors[index].map_times(&storage[index], |t,d| logic(t,d));
157        }
158    }
159
160    // key methods
161    #[inline]
162    fn step_key(&mut self, storage: &Vec<C::Storage>) {
163        for &index in self.min_key.iter() {
164            self.cursors[index].step_key(&storage[index]);
165        }
166        self.minimize_keys(storage);
167    }
168    #[inline]
169    fn seek_key(&mut self, storage: &Vec<C::Storage>, key: Self::Key<'_>) {
170        for (cursor, storage) in self.cursors.iter_mut().zip(storage) {
171            cursor.seek_key(storage, key);
172        }
173        self.minimize_keys(storage);
174    }
175
176    // value methods
177    #[inline]
178    fn step_val(&mut self, storage: &Vec<C::Storage>) {
179        for &index in self.min_val.iter() {
180            self.cursors[index].step_val(&storage[index]);
181        }
182        self.minimize_vals(storage);
183    }
184    #[inline]
185    fn seek_val(&mut self, storage: &Vec<C::Storage>, val: Self::Val<'_>) {
186        for (cursor, storage) in self.cursors.iter_mut().zip(storage) {
187            cursor.seek_val(storage, val);
188        }
189        self.minimize_vals(storage);
190    }
191
192    // rewinding methods
193    #[inline]
194    fn rewind_keys(&mut self, storage: &Vec<C::Storage>) {
195        for (cursor, storage) in self.cursors.iter_mut().zip(storage) {
196            cursor.rewind_keys(storage);
197        }
198        self.minimize_keys(storage);
199    }
200    #[inline]
201    fn rewind_vals(&mut self, storage: &Vec<C::Storage>) {
202        for &index in self.min_key.iter() {
203            self.cursors[index].rewind_vals(&storage[index]);
204        }
205        self.minimize_vals(storage);
206    }
207}