Skip to main content

differential_dataflow/columnar/
trie_merger.rs

1//! Trie-native merging primitives for sorted, consolidated `UpdatesTyped`.
2//!
3//! The columnar [`Chunk`](crate::trace::chunk::Chunk) impl drives these: `merge_pair`
4//! merges one input fully and a prefix of the other, `suffix_chunk` materializes the
5//! survivor's leftover, `extract` partitions by frontier, and `split_at` cuts a chunk.
6//! `survey` maps the interleaving of the two inputs at each trie layer, and
7//! `write_from_surveys` (via `write_layer` and `write_diffs`) copies the ranges the
8//! surveys identify into the output trie.
9
10use columnar::{Columnar, Len};
11use timely::progress::frontier::{Antichain, AntichainRef};
12
13use super::layout::ColumnarUpdate as Update;
14use super::updates::UpdatesTyped;
15
16/// Partition `merged` into chunks ready to ship (times strictly less than `upper`)
17/// and chunks kept for future seals (times at-or-after `upper`), updating
18/// `frontier` to the antichain of kept times. `merged` is consumed lazily,
19/// and outputs flow through `ship` / `kept` sinks so the caller can spill or
20/// forward as chunks are produced rather than buffering them.
21pub fn extract<U, I, FShip, FKept>(
22    merged: I,
23    upper: AntichainRef<U::Time>,
24    frontier: &mut Antichain<U::Time>,
25    mut ship: FShip,
26    mut kept: FKept,
27)
28where
29    U: Update,
30    U::Time: 'static,
31    I: IntoIterator<Item = UpdatesTyped<U>>,
32    FShip: FnMut(UpdatesTyped<U>),
33    FKept: FnMut(UpdatesTyped<U>),
34{
35    use columnar::{Container, ContainerOf, Index, Push};
36    use columnar::primitive::offsets::Strides;
37    use crate::columnar::updates::{Lists, retain_items};
38
39    // TODO: rework to move from trie structure to trie structure.
40    let mut time_owned = U::Time::default();
41    let mut bitmap = Vec::new();    // update should be kept.
42    for chunk in merged {
43        bitmap.clear();
44        let view = chunk.view();
45        let times = view.times.values;
46        for idx in 0 .. times.len() {
47            Columnar::copy_from(&mut time_owned, times.get(idx));
48            if upper.less_equal(&time_owned) {
49                frontier.insert_ref(&time_owned);
50                bitmap.push(true);
51            }
52            else { bitmap.push(false); }
53        }
54        if bitmap.iter().all(|x| *x) { kept(chunk); }
55        else if bitmap.iter().all(|x| !*x) { ship(chunk); }
56        else {
57
58            let (times, temp) = retain_items::<ContainerOf<U::Time>>(view.times, &bitmap[..]);
59            let (vals, temp) = retain_items::<ContainerOf<U::Val>>(view.vals, &temp[..]);
60            let (keys, _temp) = retain_items::<ContainerOf<U::Key>>(view.keys, &temp[..]);
61            let d_borrow = view.diffs;
62            let mut diffs = <Lists::<ContainerOf<U::Diff>> as Container>::with_capacity_for([d_borrow].into_iter());
63            for (index, bit) in bitmap.iter().enumerate() {
64                if *bit { diffs.values.push(d_borrow.values.get(index)); }
65            }
66            diffs.bounds = Strides::new(1, times.values.len() as u64);
67            kept(UpdatesTyped {
68                keys,
69                vals,
70                times,
71                diffs,
72            });
73
74            for bit in bitmap.iter_mut() { *bit = !*bit; }
75
76            let (times, temp) = retain_items::<ContainerOf<U::Time>>(view.times, &bitmap[..]);
77            let (vals, temp) = retain_items::<ContainerOf<U::Val>>(view.vals, &temp[..]);
78            let (keys, _temp) = retain_items::<ContainerOf<U::Key>>(view.keys, &temp[..]);
79            let d_borrow = view.diffs;
80            let mut diffs = <Lists::<ContainerOf<U::Diff>> as Container>::with_capacity_for([d_borrow].into_iter());
81            for (index, bit) in bitmap.iter().enumerate() {
82                if *bit { diffs.values.push(d_borrow.values.get(index)); }
83            }
84            diffs.bounds = Strides::new(1, times.values.len() as u64);
85            ship(UpdatesTyped {
86                keys,
87                vals,
88                times,
89                diffs,
90            });
91        }
92    }
93}
94
95/// Reconstruct `batch[cursor..]` as a fresh standalone `UpdatesTyped`, where
96/// `cursor` is a `(key, val, time)` index triple into `batch`'s flat columns.
97///
98/// Used to materialize the unconsumed suffix of a merge survivor: for the
99/// [`Chunk`](crate::trace::chunk::Chunk) deque protocol, the chunk pushed back
100/// to the front of an input deque.
101pub fn suffix_chunk<U: Update>(cursor: (usize, usize, usize), batch: &UpdatesTyped<U>) -> UpdatesTyped<U>
102where
103    U::Time: 'static,
104{
105    let (k, v, t) = cursor;
106    let view = batch.view();
107    let empty: UpdatesTyped<U> = Default::default();
108    let mut out = UpdatesTyped::<U>::default();
109    write_from_surveys(
110        batch,
111        &empty,
112        &[Report::This(0, 1)],
113        &[Report::This(k, view.keys.values.len())],
114        &[Report::This(v, view.vals.values.len())],
115        &[Report::This(t, view.times.values.len())],
116        &mut out,
117    );
118    out
119}
120
121/// Merge two batches, one completely and the other through the corresponding
122/// prefix, returning the merged output and leaving each input's unconsumed
123/// suffix in `batch1` / `batch2` (via an updated `(key, val, time)` cursor) or
124/// `None` if it was fully consumed.
125///
126/// Driven by the columnar [`Chunk`](crate::trace::chunk::Chunk) impl's `merge`,
127/// which materializes the surviving suffix with [`suffix_chunk`] and pushes it
128/// back to its deque.
129#[inline(never)]
130pub fn merge_pair<U: Update>(
131    batch1: &mut Option<((usize, usize, usize), UpdatesTyped<U>)>,
132    batch2: &mut Option<((usize, usize, usize), UpdatesTyped<U>)>,
133) -> UpdatesTyped<U>
134where
135    U::Time: 'static,
136{
137    // TODO: Optimization for one batch exceeding the other.
138
139    let ((k0_idx, v0_idx, t0_idx), updates0) = batch1.take().unwrap();
140    let ((k1_idx, v1_idx, t1_idx), updates1) = batch2.take().unwrap();
141
142    let view0 = updates0.view();
143    let view1 = updates1.view();
144    let keys0 = view0.keys;
145    let keys1 = view1.keys;
146    let vals0 = view0.vals;
147    let vals1 = view1.vals;
148    let times0 = view0.times;
149    let times1 = view1.times;
150
151    // Survey the interleaving of the two inputs.
152    let mut key_survey = survey::<columnar::ContainerOf<U::Key>>(keys0, keys1, &[Report::Both(0,0)]);
153    let mut val_survey = survey::<columnar::ContainerOf<U::Val>>(vals0, vals1, &key_survey);
154    let mut time_survey = survey::<columnar::ContainerOf<U::Time>>(times0, times1, &val_survey);
155
156    // We now know enough to start writing into an output batch.
157    // We should update the input surveys to reflect the subset
158    // of data that we want.
159    //
160    // At most one cursor should be non-zero (assert!).
161    // A non-zero cursor must correspond to the first entry of the surveys,
162    // as there is at least one consumed update that precedes the other batch.
163    // We need to nudge that report forward to align with the cursor, potentially
164    // squeezing the report to nothing (to the upper bound).
165
166    // We start by updating the surveys to reflect the cursors.
167    // If either cursor is set, then its batch has an element strictly less than the other batch.
168    // We therefore expect to find a prefix of This/That at the start of the survey.
169    if (k0_idx, v0_idx, t0_idx) != (0,0,0) {
170        let mut done = false; while !done { if let Report::This(l,u) = &mut key_survey[0] { if *u <= k0_idx { key_survey.remove(0); } else { *l = k0_idx; done = true; } } else { done = true; } }
171        let mut done = false; while !done { if let Report::This(l,u) = &mut val_survey[0] { if *u <= v0_idx { val_survey.remove(0); } else { *l = v0_idx; done = true; } } else { done = true; } }
172        let mut done = false; while !done { if let Report::This(l,u) = &mut time_survey[0] { if *u <= t0_idx { time_survey.remove(0); } else { *l = t0_idx; done = true; } } else { done = true; } }
173    }
174
175    if (k1_idx, v1_idx, t1_idx) != (0,0,0) {
176        let mut done = false; while !done { if let Report::That(l,u) = &mut key_survey[0] { if *u <= k1_idx { key_survey.remove(0); } else { *l = k1_idx; done = true; } } else { done = true; } }
177        let mut done = false; while !done { if let Report::That(l,u) = &mut val_survey[0] { if *u <= v1_idx { val_survey.remove(0); } else { *l = v1_idx; done = true; } } else { done = true; } }
178        let mut done = false; while !done { if let Report::That(l,u) = &mut time_survey[0] { if *u <= t1_idx { time_survey.remove(0); } else { *l = t1_idx; done = true; } } else { done = true; } }
179    }
180
181    // We want to trim the tails of the surveys to only cover ranges present in both inputs.
182    // We can determine which was "longer" by looking at the last entry of the bottom layer,
183    // which tells us which input (or both) contained the last element.
184    //
185    // From the bottom layer up, we'll identify the index of the last item, and then determine
186    // the index of the list it belongs to. We use that index in the next layer, to locate the
187    // index of the list it belongs to, on upward.
188    let next_cursor = match time_survey.last().unwrap() {
189        Report::This(_,_) => {
190            // Collect the last value indexes known to strictly exceed an entry in the other batch.
191            let mut t = times0.values.len();
192            while let Some(Report::This(l,_)) = time_survey.last() { t = *l; time_survey.pop(); }
193            let mut v = vals0.values.len();
194            while let Some(Report::This(l,_)) = val_survey.last() { v = *l; val_survey.pop(); }
195            let mut k = keys0.values.len();
196            while let Some(Report::This(l,_)) = key_survey.last() { k = *l; key_survey.pop(); }
197            // Now we may need to correct by nudging down.
198            if v == times0.len() || times0.bounds.bounds(v).0 > t { v -= 1; }
199            if k == vals0.len() || vals0.bounds.bounds(k).0 > v { k -= 1; }
200            Some(Ok((k,v,t)))
201        }
202        Report::Both(_,_) => { None }
203        Report::That(_,_) => {
204            // Collect the last value indexes known to strictly exceed an entry in the other batch.
205            let mut t = times1.values.len();
206            while let Some(Report::That(l,_)) = time_survey.last() { t = *l; time_survey.pop(); }
207            let mut v = vals1.values.len();
208            while let Some(Report::That(l,_)) = val_survey.last() { v = *l; val_survey.pop(); }
209            let mut k = keys1.values.len();
210            while let Some(Report::That(l,_)) = key_survey.last() { k = *l; key_survey.pop(); }
211            // Now we may need to correct by nudging down.
212            if v == times1.len() || times1.bounds.bounds(v).0 > t { v -= 1; }
213            if k == vals1.len() || vals1.bounds.bounds(k).0 > v { k -= 1; }
214            Some(Err((k,v,t)))
215        }
216    };
217
218    // Having updated the surveys, we now copy over the ranges they identify.
219    let mut out_batch = UpdatesTyped::<U>::default();
220    // TODO: We should be able to size `out_batch` pretty accurately from the survey.
221    write_from_surveys(&updates0, &updates1, &[Report::Both(0,0)], &key_survey, &val_survey, &time_survey, &mut out_batch);
222
223    match next_cursor {
224        Some(Ok(kvt)) => { *batch1 = Some((kvt, updates0)); }
225        Some(Err(kvt)) => {*batch2 = Some((kvt, updates1)); }
226        None => { }
227    }
228
229    out_batch
230}
231
232/// Write merged output from four levels of survey reports.
233///
234/// Each layer is written independently: `write_layer` handles keys, vals,
235/// and times; `write_diffs` handles diff consolidation.
236#[inline(never)]
237fn write_from_surveys<U: Update>(
238    updates0: &UpdatesTyped<U>,
239    updates1: &UpdatesTyped<U>,
240    root_survey: &[Report],
241    key_survey: &[Report],
242    val_survey: &[Report],
243    time_survey: &[Report],
244    output: &mut UpdatesTyped<U>,
245) {
246    let view0 = updates0.view();
247    let view1 = updates1.view();
248    write_layer(view0.keys, view1.keys, root_survey, key_survey, &mut output.keys);
249    write_layer(view0.vals, view1.vals, key_survey, val_survey, &mut output.vals);
250    write_layer(view0.times, view1.times, val_survey, time_survey, &mut output.times);
251    write_diffs::<U>(view0.diffs, view1.diffs, time_survey, &mut output.diffs);
252}
253
254/// From two sequences of interleaved lists, map out the interleaving of their values.
255///
256/// The sequence of input reports identify constraints on the sorted order of lists in the two inputs,
257/// callout out ranges of each that are exclusively order, and elements that have equal prefixes and
258/// therefore "overlap" and should be further investigated through the values of the lists.
259///
260/// The output should have the same form but for the next layer: subject to the ordering of `reports`,
261/// a similar report for the values of the two lists, appropriate for the next layer.
262#[inline(never)]
263pub fn survey<'a, C: columnar::Container<Ref<'a>: Ord>>(
264    lists0: <super::updates::Lists<C> as columnar::Borrow>::Borrowed<'a>,
265    lists1: <super::updates::Lists<C> as columnar::Borrow>::Borrowed<'a>,
266    reports: &[Report],
267) -> Vec<Report> {
268    use columnar::Index;
269    let mut output = Vec::with_capacity(reports.len()); // may grow larger, but at least this large.
270    for report in reports.iter() {
271        match report {
272            Report::This(lower0, upper0) => {
273                let (new_lower, _) = lists0.bounds.bounds(*lower0);
274                let (_, new_upper) = lists0.bounds.bounds(*upper0-1);
275                output.push(Report::This(new_lower, new_upper));
276            }
277            Report::Both(index0, index1) => {
278
279                // Fetch the bounds from the layers.
280                let (mut lower0, upper0) = lists0.bounds.bounds(*index0);
281                let (mut lower1, upper1) = lists1.bounds.bounds(*index1);
282
283                // Scour the intersecting range for matches.
284                while lower0 < upper0 && lower1 < upper1 {
285                    let val0 = lists0.values.get(lower0);
286                    let val1 = lists1.values.get(lower1);
287                    match val0.cmp(&val1) {
288                        std::cmp::Ordering::Less => {
289                            let start = lower0;
290                            lower0 += 1;
291                            gallop(lists0.values, &mut lower0, upper0, |x| x < val1);
292                            output.push(Report::This(start, lower0));
293                        },
294                        std::cmp::Ordering::Equal => {
295                            output.push(Report::Both(lower0, lower1));
296                            lower0 += 1;
297                            lower1 += 1;
298                        },
299                        std::cmp::Ordering::Greater => {
300                            let start = lower1;
301                            lower1 += 1;
302                            gallop(lists1.values, &mut lower1, upper1, |x| x < val0);
303                            output.push(Report::That(start, lower1));
304                        },
305                    }
306                }
307                if lower0 < upper0 { output.push(Report::This(lower0, upper0)); }
308                if lower1 < upper1 { output.push(Report::That(lower1, upper1)); }
309
310            }
311            Report::That(lower1, upper1) => {
312                let (new_lower, _) = lists1.bounds.bounds(*lower1);
313                let (_, new_upper) = lists1.bounds.bounds(*upper1-1);
314                output.push(Report::That(new_lower, new_upper));
315            }
316        }
317    }
318
319    output
320}
321
322/// Write one layer of merged output from a list survey and item survey.
323///
324/// The list survey describes which lists to produce (from the layer above).
325/// The item survey describes how the items within those lists interleave.
326/// Both surveys are consumed completely; a mismatch is a bug.
327///
328/// Pruning (from cursor adjustments) can affect the first and last list
329/// survey entries: the item survey's ranges may not match the natural
330/// bounds of those lists. Middle entries are guaranteed unpruned and can
331/// be bulk-copied.
332#[inline(never)]
333pub fn write_layer<'a, C: columnar::Container<Ref<'a>: Ord>>(
334    lists0: <super::updates::Lists<C> as columnar::Borrow>::Borrowed<'a>,
335    lists1: <super::updates::Lists<C> as columnar::Borrow>::Borrowed<'a>,
336    list_survey: &[Report],
337    item_survey: &[Report],
338    output: &mut super::updates::Lists<C>,
339) {
340    use columnar::{Container, Index};
341
342    let mut item_idx = 0;
343
344    for (pos, list_report) in list_survey.iter().enumerate() {
345        let is_first = pos == 0;
346        let is_last = pos == list_survey.len() - 1;
347        let may_be_pruned = is_first || is_last;
348
349        match list_report {
350            Report::This(lo, hi) => {
351                let Report::This(item_lo, item_hi) = item_survey[item_idx] else { unreachable!("Expected This in item survey for This list") };
352                item_idx += 1;
353                if may_be_pruned {
354                    // Item range may not match natural bounds; copy items in bulk
355                    // but compute per-list bounds from natural bounds clamped to
356                    // the item range.
357                    let base = output.values.len();
358                    output.values.extend_from_self(lists0.values, item_lo..item_hi);
359                    for i in *lo..*hi {
360                        let (_, nat_hi) = lists0.bounds.bounds(i);
361                        output.bounds.push((base + nat_hi.min(item_hi) - item_lo) as u64);
362                    }
363                } else {
364                    output.extend_from_self(lists0, *lo..*hi);
365                }
366            }
367            Report::That(lo, hi) => {
368                let Report::That(item_lo, item_hi) = item_survey[item_idx] else { unreachable!("Expected That in item survey for That list") };
369                item_idx += 1;
370                if may_be_pruned {
371                    let base = output.values.len();
372                    output.values.extend_from_self(lists1.values, item_lo..item_hi);
373                    for i in *lo..*hi {
374                        let (_, nat_hi) = lists1.bounds.bounds(i);
375                        output.bounds.push((base + nat_hi.min(item_hi) - item_lo) as u64);
376                    }
377                } else {
378                    output.extend_from_self(lists1, *lo..*hi);
379                }
380            }
381            Report::Both(i0, i1) => {
382                // Merge: consume item survey entries until both sides are covered.
383                let (mut c0, end0) = lists0.bounds.bounds(*i0);
384                let (mut c1, end1) = lists1.bounds.bounds(*i1);
385                while (c0 < end0 || c1 < end1) && item_idx < item_survey.len() {
386                    match item_survey[item_idx] {
387                        Report::This(lo, hi) => {
388                            if lo >= end0 { break; }
389                            output.values.extend_from_self(lists0.values, lo..hi);
390                            c0 = hi;
391                        }
392                        Report::That(lo, hi) => {
393                            if lo >= end1 { break; }
394                            output.values.extend_from_self(lists1.values, lo..hi);
395                            c1 = hi;
396                        }
397                        Report::Both(v0, v1) => {
398                            if v0 >= end0 && v1 >= end1 { break; }
399                            output.values.push(lists0.values.get(v0));
400                            c0 = v0 + 1;
401                            c1 = v1 + 1;
402                        }
403                    }
404                    item_idx += 1;
405                }
406                output.bounds.push(output.values.len() as u64);
407            }
408        }
409    }
410}
411
412/// Write the diff layer from a time survey and two diff inputs.
413///
414/// The time survey is the item-level survey for the time layer, which
415/// doubles as the list survey for diffs (one diff list per time entry).
416///
417/// - `This(lo, hi)`: bulk-copy diff lists from input 0.
418/// - `That(lo, hi)`: bulk-copy diff lists from input 1.
419/// - `Both(t0, t1)`: consolidate the two singleton diffs. Push `[sum]`
420///   if non-zero, or an empty list `[]` if they cancel.
421#[inline(never)]
422pub fn write_diffs<U: super::layout::ColumnarUpdate>(
423    diffs0: <super::updates::Lists<columnar::ContainerOf<U::Diff>> as columnar::Borrow>::Borrowed<'_>,
424    diffs1: <super::updates::Lists<columnar::ContainerOf<U::Diff>> as columnar::Borrow>::Borrowed<'_>,
425    time_survey: &[Report],
426    output: &mut super::updates::Lists<columnar::ContainerOf<U::Diff>>,
427) {
428    use columnar::{Columnar, Container, Index, Len, Push};
429    use crate::difference::{Semigroup, IsZero};
430
431    for report in time_survey.iter() {
432        match report {
433            Report::This(lo, hi) => { output.extend_from_self(diffs0, *lo..*hi); }
434            Report::That(lo, hi) => { output.extend_from_self(diffs1, *lo..*hi); }
435            Report::Both(t0, t1) => {
436                // Read singleton diffs via list bounds, consolidate.
437                let (d0_lo, d0_hi) = diffs0.bounds.bounds(*t0);
438                let (d1_lo, d1_hi) = diffs1.bounds.bounds(*t1);
439                assert_eq!(d0_hi - d0_lo, 1, "Expected singleton diff list at t0={t0}");
440                assert_eq!(d1_hi - d1_lo, 1, "Expected singleton diff list at t1={t1}");
441                let mut diff: U::Diff = Columnar::into_owned(diffs0.values.get(d0_lo));
442                diff.plus_equals(&Columnar::into_owned(diffs1.values.get(d1_lo)));
443                if !diff.is_zero() { output.values.push(&diff); }
444                output.bounds.push(output.values.len() as u64);
445            }
446        }
447    }
448}
449
450/// Increments `index` until just after the last element of `input` to satisfy `cmp`.
451///
452/// The method assumes that `cmp` is monotonic, never becoming true once it is false.
453/// If an `upper` is supplied, it acts as a constraint on the interval of `input` explored.
454#[inline(always)]
455pub(crate) fn gallop<C: columnar::Index>(input: C, lower: &mut usize, upper: usize, mut cmp: impl FnMut(<C as columnar::Index>::Ref) -> bool) {
456    // if empty input, or already >= element, return
457    if *lower < upper && cmp(input.get(*lower)) {
458        let mut step = 1;
459        while *lower + step < upper && cmp(input.get(*lower + step)) {
460            *lower += step;
461            step <<= 1;
462        }
463
464        step >>= 1;
465        while step > 0 {
466            if *lower + step < upper && cmp(input.get(*lower + step)) {
467                *lower += step;
468            }
469            step >>= 1;
470        }
471
472        *lower += 1;
473    }
474}
475
476/// A report we would expect to see in a sequence about two layers.
477///
478/// A sequence of these reports reveal an ordered traversal of the keys
479/// of two layers, with ranges exclusive to one, ranges exclusive to the
480/// other, and individual elements (not ranges) common to both.
481#[derive(Copy, Clone, columnar::Columnar, Debug)]
482pub enum Report {
483    /// Range of indices in this input.
484    This(usize, usize),
485    /// Range of indices in that input.
486    That(usize, usize),
487    /// Matching indices in both inputs.
488    Both(usize, usize),
489}
490
491/// Split `chunk` into two `UpdatesTyped` parts at record index `n`: the first
492/// `n` records and the remaining `chunk.len() - n`. Bitmap pattern mirrors
493/// `extract`'s split between ship/kept halves.
494pub fn split_at<U: Update>(chunk: UpdatesTyped<U>, n: usize) -> (UpdatesTyped<U>, UpdatesTyped<U>)
495where
496    U::Time: 'static,
497{
498    use columnar::{Container, ContainerOf, Index, Push};
499    use columnar::primitive::offsets::Strides;
500    use crate::columnar::updates::{Lists, retain_items};
501
502    let total = chunk.len();
503    if n == 0 { return (UpdatesTyped::default(), chunk); }
504    if n >= total { return (chunk, UpdatesTyped::default()); }
505
506    let view = chunk.view();
507    let mut bitmap: Vec<bool> = (0..total).map(|i| i < n).collect();
508
509    // First half: records [0, n).
510    let (times, temp) = retain_items::<ContainerOf<U::Time>>(view.times, &bitmap[..]);
511    let (vals, temp) = retain_items::<ContainerOf<U::Val>>(view.vals, &temp[..]);
512    let (keys, _temp) = retain_items::<ContainerOf<U::Key>>(view.keys, &temp[..]);
513    let d_borrow = view.diffs;
514    let mut diffs = <Lists::<ContainerOf<U::Diff>> as Container>::with_capacity_for([d_borrow].into_iter());
515    for (i, &bit) in bitmap.iter().enumerate() {
516        if bit { diffs.values.push(d_borrow.values.get(i)); }
517    }
518    diffs.bounds = Strides::new(1, times.values.len() as u64);
519    let first = UpdatesTyped { keys, vals, times, diffs };
520
521    // Invert and build second half: records [n, total).
522    for bit in bitmap.iter_mut() { *bit = !*bit; }
523    let (times, temp) = retain_items::<ContainerOf<U::Time>>(view.times, &bitmap[..]);
524    let (vals, temp) = retain_items::<ContainerOf<U::Val>>(view.vals, &temp[..]);
525    let (keys, _temp) = retain_items::<ContainerOf<U::Key>>(view.keys, &temp[..]);
526    let mut diffs = <Lists::<ContainerOf<U::Diff>> as Container>::with_capacity_for([d_borrow].into_iter());
527    for (i, &bit) in bitmap.iter().enumerate() {
528        if bit { diffs.values.push(d_borrow.values.get(i)); }
529    }
530    diffs.bounds = Strides::new(1, times.values.len() as u64);
531    let second = UpdatesTyped { keys, vals, times, diffs };
532
533    (first, second)
534}