@@ -13,7 +13,7 @@ use std::sync::LazyLock;
1313
1414use differential_dataflow:: trace:: implementations:: BatchContainer ;
1515use differential_dataflow:: trace:: { BatchReader , Cursor } ;
16- use itertools:: { Either , EitherOrBoth } ;
16+ use itertools:: EitherOrBoth ;
1717use maplit:: btreemap;
1818use mz_ore:: cast:: CastFrom ;
1919use mz_repr:: {
@@ -68,18 +68,12 @@ where
6868 befores. sort_by_key ( |( t, _v, _diff) | * t) ;
6969 afters. sort_by_key ( |( t, _v, _diff) | * t) ;
7070
71- // Fan `(time, val, count)` out to `count` copies of `(time, val)`.
72- // `iter::repeat(x).take(n)` clones on every `next()` — including the
73- // first — so using it with `count == 1` (the snapshot common case)
74- // does a gratuitous clone. `iter::once` moves the value; we only
75- // fall back to `iter::repeat` when fan-out is actually needed.
76- let fan_out = |( t, v, cnt) : ( B :: Time , B :: ValOwn , usize ) | {
77- if cnt == 1 {
78- Either :: Left ( iter:: once ( ( t, v) ) )
79- } else {
80- Either :: Right ( iter:: repeat ( ( t, v) ) . take ( cnt) )
81- }
82- } ;
71+ // The use of `repeat_n()` here is a bit subtle, but load bearing.
72+ // In the common case, cnt = 1, and we want to avoid cloning the value if possible. In the naive
73+ // implementation, we might use `iter::repeat((t, v)).take(cnt)`, but that would clone `v` `cnt` times even
74+ // when `cnt = 1`. By contrast, `repeat_n((t, v), cnt)` will return the original `(t, v)` when `cnt = 1`,
75+ // and only clone when `cnt > 1`.
76+ let fan_out = |( t, v, cnt) : ( B :: Time , B :: ValOwn , usize ) | iter:: repeat_n ( ( t, v) , cnt) ;
8377 let befores_iter = befores. drain ( ..) . flat_map ( fan_out) ;
8478 let afters_iter = afters. drain ( ..) . flat_map ( fan_out) ;
8579
0 commit comments