1use columnar::{Columnar, Container, ContainerOf, Vecs, Borrow, Index, IndexAs, Len, Push};
12use columnar::primitive::offsets::Strides;
13use crate::difference::{Semigroup, IsZero};
14
15use super::layout::ColumnarUpdate as Update;
16
17pub type Lists<C> = Vecs<C, Strides>;
19
20pub fn retain_items<'a, C: Container>(lists: <Lists<C> as Borrow>::Borrowed<'a>, keep: &[bool]) -> (Lists<C>, Vec<bool>) {
22
23 let mut output = <Lists::<C> as Container>::with_capacity_for([lists].into_iter());
25 let mut bitmap = Vec::with_capacity(lists.len());
26 assert_eq!(keep.len(), lists.values.len());
27 for list_index in 0 .. lists.len() {
28 let (lower, upper) = lists.bounds.bounds(list_index);
29 for item_index in lower .. upper {
30 if keep[item_index] {
31 output.values.push(lists.values.get(item_index));
32 }
33 }
34 if output.values.len() > columnar::Index::last(&output.bounds.borrow()).unwrap_or(0) as usize {
35 output.bounds.push(output.values.len() as u64);
36 bitmap.push(true);
37 }
38 else { bitmap.push(false); }
39 }
40
41 assert_eq!(bitmap.len(), lists.len());
42 (output, bitmap)
43}
44
45
46pub struct UpdatesTyped<U: Update> {
59 pub keys: Lists<ContainerOf<U::Key>>,
61 pub vals: Lists<ContainerOf<U::Val>>,
63 pub times: Lists<ContainerOf<U::Time>>,
65 pub diffs: Lists<ContainerOf<U::Diff>>,
67}
68
69impl<U: Update> Default for UpdatesTyped<U> {
70 fn default() -> Self {
71 Self {
72 keys: Default::default(),
73 vals: Default::default(),
74 times: Default::default(),
75 diffs: Default::default(),
76 }
77 }
78}
79
80impl<U: Update> std::fmt::Debug for UpdatesTyped<U> {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 f.debug_struct("UpdatesTyped").finish()
83 }
84}
85
86impl<U: Update> Clone for UpdatesTyped<U> {
87 fn clone(&self) -> Self {
88 Self {
89 keys: self.keys.clone(),
90 vals: self.vals.clone(),
91 times: self.times.clone(),
92 diffs: self.diffs.clone(),
93 }
94 }
95}
96
97pub struct UpdatesView<'a, U: Update> {
104 pub keys: <Lists<ContainerOf<U::Key>> as Borrow>::Borrowed<'a>,
106 pub vals: <Lists<ContainerOf<U::Val>> as Borrow>::Borrowed<'a>,
108 pub times: <Lists<ContainerOf<U::Time>> as Borrow>::Borrowed<'a>,
110 pub diffs: <Lists<ContainerOf<U::Diff>> as Borrow>::Borrowed<'a>,
112}
113
114impl<'a, U: Update> Copy for UpdatesView<'a, U> {}
115impl<'a, U: Update> Clone for UpdatesView<'a, U> { fn clone(&self) -> Self { *self } }
116
117impl<'a, U: Update> UpdatesView<'a, U> {
118 pub fn iter(self) -> UpdatesIter<'a, U> {
125 let leaves = Len::len(&self.diffs.values);
128 let (v_end, t_end, d_end) = if leaves > 0 {
129 (self.vals.bounds.index_as(0) as usize,
130 self.times.bounds.index_as(0) as usize,
131 self.diffs.bounds.index_as(0) as usize)
132 } else { (0, 0, 0) };
133 UpdatesIter { view: self, k: 0, v: 0, t: 0, d: 0, v_end, t_end, d_end, leaves }
134 }
135
136 pub fn vals_bounds(self, key_range: std::ops::Range<usize>) -> std::ops::Range<usize> {
138 if !key_range.is_empty() {
139 let bounds = self.vals.bounds;
140 let lower = if key_range.start == 0 { 0 } else { bounds.index_as(key_range.start - 1) as usize };
141 let upper = bounds.index_as(key_range.end - 1) as usize;
142 lower..upper
143 } else { key_range }
144 }
145 pub fn times_bounds(self, val_range: std::ops::Range<usize>) -> std::ops::Range<usize> {
147 if !val_range.is_empty() {
148 let bounds = self.times.bounds;
149 let lower = if val_range.start == 0 { 0 } else { bounds.index_as(val_range.start - 1) as usize };
150 let upper = bounds.index_as(val_range.end - 1) as usize;
151 lower..upper
152 } else { val_range }
153 }
154}
155
156pub struct UpdatesIter<'a, U: Update> {
164 view: UpdatesView<'a, U>,
165 k: usize, v: usize, t: usize, d: usize,
166 v_end: usize, t_end: usize, d_end: usize,
167 leaves: usize,
168}
169
170impl<'a, U: Update> Iterator for UpdatesIter<'a, U> {
171 type Item = (
172 columnar::Ref<'a, U::Key>,
173 columnar::Ref<'a, U::Val>,
174 columnar::Ref<'a, U::Time>,
175 columnar::Ref<'a, U::Diff>,
176 );
177
178 #[inline]
179 fn next(&mut self) -> Option<Self::Item> {
180 if self.d >= self.leaves { return None; }
181 while self.d >= self.d_end {
185 self.t += 1;
186 while self.t >= self.t_end {
187 self.v += 1;
188 while self.v >= self.v_end {
189 self.k += 1;
190 self.v_end = self.view.vals.bounds.index_as(self.k) as usize;
191 }
192 self.t_end = self.view.times.bounds.index_as(self.v) as usize;
193 }
194 self.d_end = self.view.diffs.bounds.index_as(self.t) as usize;
195 }
196 let item = (
197 self.view.keys.values.get(self.k),
198 self.view.vals.values.get(self.v),
199 self.view.times.values.get(self.t),
200 self.view.diffs.values.get(self.d),
201 );
202 self.d += 1;
203 Some(item)
204 }
205
206 #[inline]
207 fn size_hint(&self) -> (usize, Option<usize>) {
208 let rem = self.leaves - self.d;
209 (rem, Some(rem))
210 }
211}
212
213impl<'a, U: Update> ExactSizeIterator for UpdatesIter<'a, U> {}
214
215impl<U: Update> UpdatesTyped<U> {
216 pub fn view(&self) -> UpdatesView<'_, U> {
218 UpdatesView {
219 keys: self.keys.borrow(),
220 vals: self.vals.borrow(),
221 times: self.times.borrow(),
222 diffs: self.diffs.borrow(),
223 }
224 }
225}
226
227pub struct Updates<U: Update, B = timely::bytes::arc::Bytes> {
235 pub keys: columnar::bytes::stash::Stash<Lists<ContainerOf<U::Key>>, B>,
237 pub vals: columnar::bytes::stash::Stash<Lists<ContainerOf<U::Val>>, B>,
239 pub times: columnar::bytes::stash::Stash<Lists<ContainerOf<U::Time>>, B>,
241 pub diffs: columnar::bytes::stash::Stash<Lists<ContainerOf<U::Diff>>, B>,
243}
244
245impl<U: Update, B> Default for Updates<U, B> {
246 fn default() -> Self {
247 Self {
248 keys: Default::default(),
249 vals: Default::default(),
250 times: Default::default(),
251 diffs: Default::default(),
252 }
253 }
254}
255
256impl<U: Update, B: Clone> Clone for Updates<U, B> {
257 fn clone(&self) -> Self {
258 Self {
259 keys: self.keys.clone(),
260 vals: self.vals.clone(),
261 times: self.times.clone(),
262 diffs: self.diffs.clone(),
263 }
264 }
265}
266
267impl<U: Update> Updates<U> {
268 pub fn read_from(mut bytes: timely::bytes::arc::Bytes) -> Self {
271 use columnar::bytes::stash::Stash;
272 let header = bytes.extract_to(32);
273 let len = |i: usize| u64::from_le_bytes(header[i*8..i*8+8].try_into().unwrap()) as usize;
274 let (kl, vl, tl, dl) = (len(0), len(1), len(2), len(3));
275 let keys = Stash::try_from_bytes(bytes.extract_to(kl)).expect("keys decode");
276 let vals = Stash::try_from_bytes(bytes.extract_to(vl)).expect("vals decode");
277 let times = Stash::try_from_bytes(bytes.extract_to(tl)).expect("times decode");
278 let diffs = Stash::try_from_bytes(bytes.extract_to(dl)).expect("diffs decode");
279 Updates { keys, vals, times, diffs }
280 }
281}
282
283impl<U: Update, B> From<UpdatesTyped<U>> for Updates<U, B> {
284 fn from(owned: UpdatesTyped<U>) -> Self {
285 use columnar::bytes::stash::Stash;
286 Self {
287 keys: Stash::Typed(owned.keys),
288 vals: Stash::Typed(owned.vals),
289 times: Stash::Typed(owned.times),
290 diffs: Stash::Typed(owned.diffs),
291 }
292 }
293}
294
295impl<U: Update, B: std::ops::Deref<Target = [u8]> + Clone + 'static> Updates<U, B> {
296 pub fn view(&self) -> UpdatesView<'_, U> {
298 UpdatesView {
299 keys: self.keys.borrow(),
300 vals: self.vals.borrow(),
301 times: self.times.borrow(),
302 diffs: self.diffs.borrow(),
303 }
304 }
305
306 pub fn len(&self) -> usize {
308 self.view().diffs.values.len()
309 }
310
311 pub fn is_empty(&self) -> bool { self.len() == 0 }
313
314 pub fn write_to<W: std::io::Write>(&self, writer: &mut W) {
318 let lens = [
319 self.keys.length_in_bytes() as u64,
320 self.vals.length_in_bytes() as u64,
321 self.times.length_in_bytes() as u64,
322 self.diffs.length_in_bytes() as u64,
323 ];
324 for l in lens { writer.write_all(&l.to_le_bytes()).unwrap(); }
325 self.keys.write_bytes(writer).unwrap();
326 self.vals.write_bytes(writer).unwrap();
327 self.times.write_bytes(writer).unwrap();
328 self.diffs.write_bytes(writer).unwrap();
329 }
330
331 pub fn length_in_bytes(&self) -> usize {
333 32 + self.keys.length_in_bytes() + self.vals.length_in_bytes()
334 + self.times.length_in_bytes() + self.diffs.length_in_bytes()
335 }
336
337 pub fn into_typed(mut self) -> UpdatesTyped<U> {
342 use columnar::bytes::stash::Stash;
343 self.keys.make_typed();
344 self.vals.make_typed();
345 self.times.make_typed();
346 self.diffs.make_typed();
347 let Stash::Typed(keys) = self.keys else { unreachable!() };
348 let Stash::Typed(vals) = self.vals else { unreachable!() };
349 let Stash::Typed(times) = self.times else { unreachable!() };
350 let Stash::Typed(diffs) = self.diffs else { unreachable!() };
351 UpdatesTyped { keys, vals, times, diffs }
352 }
353}
354
355pub type Tuple<U> = (<U as Update>::Key, <U as Update>::Val, <U as Update>::Time, <U as Update>::Diff);
357
358#[inline]
360pub fn child_range<B: IndexAs<u64>>(bounds: B, i: usize) -> std::ops::Range<usize> {
361 let lower = if i == 0 { 0 } else { bounds.index_as(i - 1) as usize };
362 let upper = bounds.index_as(i) as usize;
363 lower..upper
364}
365
366pub struct Consolidating<I: Iterator, D> {
372 iter: std::iter::Peekable<I>,
373 diff: D,
374}
375
376impl<K, V, T, D, I> Consolidating<I, D>
377where
378 K: Copy + Eq,
379 V: Copy + Eq,
380 T: Copy + Eq,
381 D: Semigroup + IsZero + Default,
382 I: Iterator<Item = (K, V, T, D)>,
383{
384 pub fn new(iter: I) -> Self {
387 Self { iter: iter.peekable(), diff: D::default() }
388 }
389}
390
391impl<K, V, T, D, I> Iterator for Consolidating<I, D>
392where
393 K: Copy + Eq,
394 V: Copy + Eq,
395 T: Copy + Eq,
396 D: Semigroup + IsZero + Default + Clone,
397 I: Iterator<Item = (K, V, T, D)>,
398{
399 type Item = (K, V, T, D);
400 fn next(&mut self) -> Option<Self::Item> {
401 loop {
402 let (k, v, t, d) = self.iter.next()?;
403 self.diff = d;
404 while let Some(&(k2, v2, t2, _)) = self.iter.peek() {
405 if k2 == k && v2 == v && t2 == t {
406 let (_, _, _, d2) = self.iter.next().unwrap();
407 self.diff.plus_equals(&d2);
408 } else {
409 break;
410 }
411 }
412 if !self.diff.is_zero() {
413 return Some((k, v, t, self.diff.clone()));
414 }
415 }
416 }
417}
418
419impl<U: Update> UpdatesTyped<U> {
420
421 pub fn extend_from_keys(&mut self, other: UpdatesView<'_, U>, key_range: std::ops::Range<usize>) {
423 self.keys.values.extend_from_self(other.keys.values, key_range.clone());
424 self.vals.extend_from_self(other.vals, key_range.clone());
425 let val_range = other.vals_bounds(key_range);
426 self.times.extend_from_self(other.times, val_range.clone());
427 let time_range = other.times_bounds(val_range);
428 self.diffs.extend_from_self(other.diffs, time_range);
429 }
430
431 pub fn form_unsorted<'a>(unsorted: impl Iterator<Item = columnar::Ref<'a, Tuple<U>>>) -> Self {
433 let mut data = unsorted.collect::<Vec<_>>();
434 data.sort_unstable();
437 Self::form(data.into_iter())
438 }
439
440 pub fn form<'a>(sorted: impl Iterator<Item = columnar::Ref<'a, Tuple<U>>>) -> Self {
442
443 let consolidated = Consolidating::new(
445 sorted.map(|(k, v, t, d)| (k, v, t, <U::Diff as Columnar>::into_owned(d)))
446 );
447
448 let mut output = Self::default();
450 let mut updates = consolidated;
451 if let Some((key, val, time, diff)) = updates.next() {
452 let mut prev = (key, val, time);
453 output.keys.values.push(key);
454 output.vals.values.push(val);
455 output.times.values.push(time);
456 output.diffs.values.push(&diff);
457 output.diffs.bounds.push(output.diffs.values.len() as u64);
458
459 for (key, val, time, diff) in updates {
461
462 if key != prev.0 {
464 output.vals.bounds.push(output.vals.values.len() as u64);
465 output.times.bounds.push(output.times.values.len() as u64);
466 output.keys.values.push(key);
467 output.vals.values.push(val);
468 }
469 else if val != prev.1 {
471 output.times.bounds.push(output.times.values.len() as u64);
472 output.vals.values.push(val);
473 }
474 else {
475 assert!(time != prev.2);
477 }
478
479 output.times.values.push(time);
481 output.diffs.values.push(&diff);
482 output.diffs.bounds.push(output.diffs.values.len() as u64);
483
484 prev = (key, val, time);
485 }
486
487 output.keys.bounds.push(output.keys.values.len() as u64);
489 output.vals.bounds.push(output.vals.values.len() as u64);
490 output.times.bounds.push(output.times.values.len() as u64);
491 }
492
493 output
494 }
495
496 pub fn consolidate(self) -> Self { Self::form_unsorted(self.iter()) }
500 pub fn filter_zero(self) -> Self {
502 if self.diffs.bounds.strided() == Some(1) { self }
503 else {
505 let mut keep = Vec::with_capacity(self.times.values.len());
506 for index in 0 .. self.times.values.len() {
507 keep.push({
508 let (lower, upper) = self.diffs.bounds.bounds(index);
509 lower < upper
510 });
511 }
512 let (times, keep) = retain_items(self.times.borrow(), &keep[..]);
513 let (vals, keep) = retain_items(self.vals.borrow(), &keep[..]);
514 let (keys, _keep) = retain_items(self.keys.borrow(), &keep[..]);
515 UpdatesTyped {
516 keys,
517 vals,
518 times,
519 diffs: Lists {
520 bounds: Strides::new(1, self.diffs.values.len() as u64),
521 values: self.diffs.values,
522 },
523 }
524 }
525 }
527
528 pub fn len(&self) -> usize { self.diffs.values.len() }
530}
531
532impl<KP, VP, TP, DP, U: Update> Push<(KP, VP, TP, DP)> for UpdatesTyped<U>
537where
538 ContainerOf<U::Key>: Push<KP>,
539 ContainerOf<U::Val>: Push<VP>,
540 ContainerOf<U::Time>: Push<TP>,
541 ContainerOf<U::Diff>: Push<DP>,
542{
543 fn push(&mut self, (key, val, time, diff): (KP, VP, TP, DP)) {
544 self.keys.values.push(key);
545 self.keys.bounds.push(self.keys.values.len() as u64);
546 self.vals.values.push(val);
547 self.vals.bounds.push(self.vals.values.len() as u64);
548 self.times.values.push(time);
549 self.times.bounds.push(self.times.values.len() as u64);
550 self.diffs.values.push(diff);
551 self.diffs.bounds.push(self.diffs.values.len() as u64);
552 }
553}
554
555impl<U: Update> timely::container::PushInto<((U::Key, U::Val), U::Time, U::Diff)> for UpdatesTyped<U> {
557 fn push_into(&mut self, ((key, val), time, diff): ((U::Key, U::Val), U::Time, U::Diff)) {
558 self.push((&key, &val, &time, &diff));
559 }
560}
561
562impl<U: Update> UpdatesTyped<U> {
563
564 pub fn iter(&self) -> impl Iterator<Item = (
566 columnar::Ref<'_, U::Key>,
567 columnar::Ref<'_, U::Val>,
568 columnar::Ref<'_, U::Time>,
569 columnar::Ref<'_, U::Diff>,
570 )> {
571 self.view().iter()
572 }
573}
574
575impl<U: Update> timely::Accountable for UpdatesTyped<U> {
576 #[inline] fn record_count(&self) -> i64 { Len::len(&self.diffs.values) as i64 }
577}
578
579impl<U: Update> timely::dataflow::channels::ContainerBytes for UpdatesTyped<U> {
580 fn from_bytes(_bytes: timely::bytes::arc::Bytes) -> Self { unimplemented!() }
581 fn length_in_bytes(&self) -> usize { unimplemented!() }
582 fn into_bytes<W: std::io::Write>(&self, _writer: &mut W) { unimplemented!() }
583}
584
585pub struct UpdatesBuilder<U: Update> {
598 updates: UpdatesTyped<U>,
600}
601
602impl<U: Update> UpdatesBuilder<U> {
603 pub fn new_from(mut updates: UpdatesTyped<U>) -> Self {
609 use columnar::Len;
610 if Len::len(&updates.keys.values) > 0 {
611 updates.keys.bounds.pop();
612 updates.vals.bounds.pop();
613 updates.times.bounds.pop();
614 }
615 Self { updates }
616 }
617
618 pub fn meld(&mut self, chunk: &UpdatesTyped<U>) {
625 use columnar::{Borrow, Index, Len};
626
627 if chunk.len() == 0 { return; }
628
629 if Len::len(&self.updates.keys.values) == 0 {
631 self.updates = chunk.clone();
632 self.updates.keys.bounds.pop();
633 self.updates.vals.bounds.pop();
634 self.updates.times.bounds.pop();
635 return;
636 }
637
638 let keys_match = {
640 let skb = self.updates.keys.values.borrow();
641 let ckb = chunk.keys.values.borrow();
642 skb.get(Len::len(&skb) - 1) == ckb.get(0)
643 };
644 let vals_match = keys_match && {
645 let svb = self.updates.vals.values.borrow();
646 let cvb = chunk.vals.values.borrow();
647 svb.get(Len::len(&svb) - 1) == cvb.get(0)
648 };
649
650 let chunk_num_keys = Len::len(&chunk.keys.values);
651 let chunk_num_vals = Len::len(&chunk.vals.values);
652 let chunk_num_times = Len::len(&chunk.times.values);
653
654 let first_key_vals = child_range(chunk.vals.borrow().bounds, 0);
656 let first_val_times = child_range(chunk.times.borrow().bounds, 0);
657
658 let mut differ = false;
662
663 if keys_match {
665 if chunk_num_keys > 1 {
667 self.updates.keys.values.extend_from_self(chunk.keys.values.borrow(), 1..chunk_num_keys);
668 }
669 } else {
670 self.updates.keys.values.extend_from_self(chunk.keys.values.borrow(), 0..chunk_num_keys);
672 differ = true;
673 }
674
675 if differ {
677 self.updates.vals.bounds.push(Len::len(&self.updates.vals.values) as u64);
679 self.updates.vals.extend_from_self(chunk.vals.borrow(), 0..chunk_num_keys);
680 self.updates.vals.bounds.pop();
681 } else {
682 if vals_match {
684 if first_key_vals.len() > 1 {
686 self.updates.vals.values.extend_from_self(
687 chunk.vals.values.borrow(),
688 (first_key_vals.start + 1)..first_key_vals.end,
689 );
690 }
691 } else {
692 self.updates.vals.values.extend_from_self(
694 chunk.vals.values.borrow(),
695 first_key_vals.clone(),
696 );
697 differ = true;
698 }
699 if chunk_num_keys > 1 {
701 self.updates.vals.bounds.push(Len::len(&self.updates.vals.values) as u64);
702 self.updates.vals.extend_from_self(chunk.vals.borrow(), 1..chunk_num_keys);
703 self.updates.vals.bounds.pop();
704 }
705 }
706
707 if differ {
709 self.updates.times.bounds.push(Len::len(&self.updates.times.values) as u64);
711 self.updates.times.extend_from_self(chunk.times.borrow(), 0..chunk_num_vals);
712 self.updates.times.bounds.pop();
713 } else {
714 debug_assert!({
717 let stb = self.updates.times.values.borrow();
718 let ctb = chunk.times.values.borrow();
719 stb.get(Len::len(&stb) - 1) != ctb.get(0)
720 }, "meld: duplicate time within same (key, val)");
721 self.updates.times.values.extend_from_self(
723 chunk.times.values.borrow(),
724 first_val_times.clone(),
725 );
726 differ = true;
727 if chunk_num_vals > 1 {
729 self.updates.times.bounds.push(Len::len(&self.updates.times.values) as u64);
730 self.updates.times.extend_from_self(chunk.times.borrow(), 1..chunk_num_vals);
731 self.updates.times.bounds.pop();
732 }
733 }
734
735 debug_assert!(differ);
740 self.updates.diffs.extend_from_self(chunk.diffs.borrow(), 0..chunk_num_times);
741 }
742
743 pub fn done(mut self) -> UpdatesTyped<U> {
745 use columnar::Len;
746 if Len::len(&self.updates.keys.values) > 0 {
747 self.updates.times.bounds.push(Len::len(&self.updates.times.values) as u64);
749 self.updates.vals.bounds.push(Len::len(&self.updates.vals.values) as u64);
751 self.updates.keys.bounds.push(Len::len(&self.updates.keys.values) as u64);
753 }
754 self.updates
755 }
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761 use columnar::Push;
762
763 type TestUpdate = (u64, u64, u64, i64);
764
765 fn collect(updates: &UpdatesTyped<TestUpdate>) -> Vec<(u64, u64, u64, i64)> {
766 updates.iter().map(|(k, v, t, d)| (*k, *v, *t, *d)).collect()
767 }
768
769 #[test]
770 fn test_push_and_consolidate_basic() {
771 let mut updates = UpdatesTyped::<TestUpdate>::default();
772 updates.push((&1, &10, &100, &1));
773 updates.push((&1, &10, &100, &2));
774 updates.push((&2, &20, &200, &5));
775 assert_eq!(updates.len(), 3);
776 assert_eq!(collect(&updates.consolidate()), vec![(1, 10, 100, 3), (2, 20, 200, 5)]);
777 }
778
779 #[test]
780 fn test_cancellation() {
781 let mut updates = UpdatesTyped::<TestUpdate>::default();
782 updates.push((&1, &10, &100, &3));
783 updates.push((&1, &10, &100, &-3));
784 updates.push((&2, &20, &200, &1));
785 assert_eq!(collect(&updates.consolidate()), vec![(2, 20, 200, 1)]);
786 }
787
788 #[test]
789 fn test_multiple_vals_and_times() {
790 let mut updates = UpdatesTyped::<TestUpdate>::default();
791 updates.push((&1, &10, &100, &1));
792 updates.push((&1, &10, &200, &2));
793 updates.push((&1, &20, &100, &3));
794 updates.push((&1, &20, &100, &4));
795 assert_eq!(collect(&updates.consolidate()), vec![(1, 10, 100, 1), (1, 10, 200, 2), (1, 20, 100, 7)]);
796 }
797
798 #[test]
799 fn test_val_cancellation_propagates() {
800 let mut updates = UpdatesTyped::<TestUpdate>::default();
801 updates.push((&1, &10, &100, &5));
802 updates.push((&1, &10, &100, &-5));
803 updates.push((&1, &20, &100, &1));
804 assert_eq!(collect(&updates.consolidate()), vec![(1, 20, 100, 1)]);
805 }
806
807 #[test]
808 fn test_empty() {
809 let updates = UpdatesTyped::<TestUpdate>::default();
810 assert_eq!(collect(&updates.consolidate()), vec![]);
811 }
812
813 #[test]
814 fn test_total_cancellation() {
815 let mut updates = UpdatesTyped::<TestUpdate>::default();
816 updates.push((&1, &10, &100, &1));
817 updates.push((&1, &10, &100, &-1));
818 assert_eq!(collect(&updates.consolidate()), vec![]);
819 }
820
821 #[test]
822 fn test_unsorted_input() {
823 let mut updates = UpdatesTyped::<TestUpdate>::default();
824 updates.push((&3, &30, &300, &1));
825 updates.push((&1, &10, &100, &2));
826 updates.push((&2, &20, &200, &3));
827 assert_eq!(collect(&updates.consolidate()), vec![(1, 10, 100, 2), (2, 20, 200, 3), (3, 30, 300, 1)]);
828 }
829
830 #[test]
831 fn test_first_key_cancels() {
832 let mut updates = UpdatesTyped::<TestUpdate>::default();
833 updates.push((&1, &10, &100, &5));
834 updates.push((&1, &10, &100, &-5));
835 updates.push((&2, &20, &200, &3));
836 assert_eq!(collect(&updates.consolidate()), vec![(2, 20, 200, 3)]);
837 }
838
839 #[test]
840 fn test_middle_time_cancels() {
841 let mut updates = UpdatesTyped::<TestUpdate>::default();
842 updates.push((&1, &10, &100, &1));
843 updates.push((&1, &10, &200, &2));
844 updates.push((&1, &10, &200, &-2));
845 updates.push((&1, &10, &300, &3));
846 assert_eq!(collect(&updates.consolidate()), vec![(1, 10, 100, 1), (1, 10, 300, 3)]);
847 }
848
849 #[test]
850 fn test_first_val_cancels() {
851 let mut updates = UpdatesTyped::<TestUpdate>::default();
852 updates.push((&1, &10, &100, &1));
853 updates.push((&1, &10, &100, &-1));
854 updates.push((&1, &20, &100, &5));
855 assert_eq!(collect(&updates.consolidate()), vec![(1, 20, 100, 5)]);
856 }
857
858 #[test]
859 fn test_interleaved_cancellations() {
860 let mut updates = UpdatesTyped::<TestUpdate>::default();
861 updates.push((&1, &10, &100, &1));
862 updates.push((&1, &10, &100, &-1));
863 updates.push((&2, &20, &200, &7));
864 updates.push((&3, &30, &300, &4));
865 updates.push((&3, &30, &300, &-4));
866 assert_eq!(collect(&updates.consolidate()), vec![(2, 20, 200, 7)]);
867 }
868}