1use std::fmt::Debug;
5
6use reifydb_value::{
7 util::bitvec::BitVec,
8 value::{
9 Value,
10 container::{
11 bool::BoolContainer, number::NumberContainer, temporal::TemporalContainer, uuid::UuidContainer,
12 },
13 date::Date,
14 datetime::DateTime,
15 duration::Duration,
16 is::{IsNumber, IsTemporal, IsUuid},
17 time::Time,
18 uuid::{Uuid4, Uuid7},
19 },
20};
21
22use crate::value::column::ColumnBuffer;
23
24impl ColumnBuffer {
25 pub fn scatter_merge(
26 &self,
27 other: &ColumnBuffer,
28 then_mask: &BitVec,
29 else_mask: &BitVec,
30 total_len: usize,
31 ) -> ColumnBuffer {
32 if let (
33 ColumnBuffer::Option {
34 inner: a_inner,
35 bitvec: a_bv,
36 },
37 ColumnBuffer::Option {
38 inner: b_inner,
39 bitvec: b_bv,
40 },
41 ) = (self, other)
42 {
43 let merged_inner = a_inner.scatter_merge(b_inner, then_mask, else_mask, total_len);
44 let merged_bv = merge_validity_bitvecs(a_bv, b_bv, then_mask, else_mask, total_len);
45 return match merged_inner {
46 ColumnBuffer::Option {
47 inner: nested_inner,
48 bitvec: nested_bv,
49 } => ColumnBuffer::Option {
50 inner: nested_inner,
51 bitvec: merged_bv.and(&nested_bv),
52 },
53 inner => ColumnBuffer::Option {
54 inner: Box::new(inner),
55 bitvec: merged_bv,
56 },
57 };
58 }
59
60 if let Some(result) = scatter_merge_typed(self, other, then_mask, else_mask, total_len) {
61 return result;
62 }
63
64 scatter_merge_generic(self, other, then_mask, else_mask, total_len)
65 }
66}
67
68fn merge_validity_bitvecs(
69 then_bv: &BitVec,
70 else_bv: &BitVec,
71 then_mask: &BitVec,
72 else_mask: &BitVec,
73 total_len: usize,
74) -> BitVec {
75 let mut out = BitVec::with_capacity(total_len);
76 for i in 0..total_len {
77 let bit = if then_mask.get(i) {
78 i < then_bv.len() && then_bv.get(i)
79 } else if else_mask.get(i) {
80 i < else_bv.len() && else_bv.get(i)
81 } else {
82 false
83 };
84 out.push(bit);
85 }
86 out
87}
88
89fn scatter_merge_generic(
90 self_col: &ColumnBuffer,
91 other: &ColumnBuffer,
92 then_mask: &BitVec,
93 else_mask: &BitVec,
94 total_len: usize,
95) -> ColumnBuffer {
96 let result_type = self_col.get_type();
97 let mut data = ColumnBuffer::with_capacity(result_type.clone(), total_len);
98 for i in 0..total_len {
99 if then_mask.get(i) {
100 data.push_value(self_col.get_value(i));
101 } else if else_mask.get(i) {
102 data.push_value(other.get_value(i));
103 } else {
104 data.push_value(Value::none_of(result_type.clone()));
105 }
106 }
107 data
108}
109
110fn scatter_merge_typed(
111 self_col: &ColumnBuffer,
112 other: &ColumnBuffer,
113 then_mask: &BitVec,
114 else_mask: &BitVec,
115 total_len: usize,
116) -> Option<ColumnBuffer> {
117 macro_rules! number_kernel {
118 ($variant:ident, $t:ty) => {
119 if let (ColumnBuffer::$variant(a), ColumnBuffer::$variant(b)) = (self_col, other) {
120 let (data, validity) = number_scatter::<$t>(a, b, then_mask, else_mask, total_len);
121 let inner = ColumnBuffer::$variant(NumberContainer::new(data));
122 return Some(finalize(inner, validity));
123 }
124 };
125 }
126 macro_rules! temporal_kernel {
127 ($variant:ident, $t:ty) => {
128 if let (ColumnBuffer::$variant(a), ColumnBuffer::$variant(b)) = (self_col, other) {
129 let (data, validity) = temporal_scatter::<$t>(a, b, then_mask, else_mask, total_len);
130 let inner = ColumnBuffer::$variant(TemporalContainer::new(data));
131 return Some(finalize(inner, validity));
132 }
133 };
134 }
135 macro_rules! uuid_kernel {
136 ($variant:ident, $t:ty) => {
137 if let (ColumnBuffer::$variant(a), ColumnBuffer::$variant(b)) = (self_col, other) {
138 let (data, validity) = uuid_scatter::<$t>(a, b, then_mask, else_mask, total_len);
139 let inner = ColumnBuffer::$variant(UuidContainer::new(data));
140 return Some(finalize(inner, validity));
141 }
142 };
143 }
144
145 if let (ColumnBuffer::Bool(a), ColumnBuffer::Bool(b)) = (self_col, other) {
146 let (data, validity) = bool_scatter(a, b, then_mask, else_mask, total_len);
147 let inner = ColumnBuffer::Bool(BoolContainer::from_parts(data));
148 return Some(finalize(inner, validity));
149 }
150
151 number_kernel!(Float4, f32);
152 number_kernel!(Float8, f64);
153 number_kernel!(Int1, i8);
154 number_kernel!(Int2, i16);
155 number_kernel!(Int4, i32);
156 number_kernel!(Int8, i64);
157 number_kernel!(Int16, i128);
158 number_kernel!(Uint1, u8);
159 number_kernel!(Uint2, u16);
160 number_kernel!(Uint4, u32);
161 number_kernel!(Uint8, u64);
162 number_kernel!(Uint16, u128);
163
164 temporal_kernel!(Date, Date);
165 temporal_kernel!(DateTime, DateTime);
166 temporal_kernel!(Time, Time);
167 temporal_kernel!(Duration, Duration);
168
169 uuid_kernel!(Uuid4, Uuid4);
170 uuid_kernel!(Uuid7, Uuid7);
171
172 None
173}
174
175fn finalize(inner: ColumnBuffer, validity: Option<BitVec>) -> ColumnBuffer {
176 match validity {
177 Some(bv) => ColumnBuffer::Option {
178 inner: Box::new(inner),
179 bitvec: bv,
180 },
181 None => inner,
182 }
183}
184
185fn bool_scatter(
186 a: &BoolContainer,
187 b: &BoolContainer,
188 then_mask: &BitVec,
189 else_mask: &BitVec,
190 total_len: usize,
191) -> (BitVec, Option<BitVec>) {
192 let a_data = a.data();
193 let b_data = b.data();
194 let mut out = BitVec::with_capacity(total_len);
195 let mut validity: Option<BitVec> = None;
196 for i in 0..total_len {
197 let in_then = then_mask.get(i);
198 let in_else = !in_then && else_mask.get(i);
199 let bit = if in_then && i < a_data.len() {
200 a_data.get(i)
201 } else if in_else && i < b_data.len() {
202 b_data.get(i)
203 } else {
204 false
205 };
206 out.push(bit);
207 if !in_then && !in_else {
208 let v = validity.get_or_insert_with(|| {
209 let mut bv = BitVec::with_capacity(total_len);
210 for _ in 0..i {
211 bv.push(true);
212 }
213 bv
214 });
215 v.push(false);
216 } else if let Some(v) = validity.as_mut() {
217 v.push(true);
218 }
219 }
220 (out, validity)
221}
222
223fn number_scatter<T>(
224 a: &NumberContainer<T>,
225 b: &NumberContainer<T>,
226 then_mask: &BitVec,
227 else_mask: &BitVec,
228 total_len: usize,
229) -> (Vec<T>, Option<BitVec>)
230where
231 T: IsNumber + Clone + Default + Debug,
232{
233 let a_data = a.data();
234 let b_data = b.data();
235 let mut out: Vec<T> = Vec::with_capacity(total_len);
236 let mut validity: Option<BitVec> = None;
237 for i in 0..total_len {
238 let in_then = then_mask.get(i);
239 let in_else = !in_then && else_mask.get(i);
240 let value = if in_then {
241 a_data.get(i).cloned().unwrap_or_default()
242 } else if in_else {
243 b_data.get(i).cloned().unwrap_or_default()
244 } else {
245 T::default()
246 };
247 out.push(value);
248 if !in_then && !in_else {
249 let v = validity.get_or_insert_with(|| {
250 let mut bv = BitVec::with_capacity(total_len);
251 for _ in 0..i {
252 bv.push(true);
253 }
254 bv
255 });
256 v.push(false);
257 } else if let Some(v) = validity.as_mut() {
258 v.push(true);
259 }
260 }
261 (out, validity)
262}
263
264fn temporal_scatter<T>(
265 a: &TemporalContainer<T>,
266 b: &TemporalContainer<T>,
267 then_mask: &BitVec,
268 else_mask: &BitVec,
269 total_len: usize,
270) -> (Vec<T>, Option<BitVec>)
271where
272 T: IsTemporal + Clone + Default + Debug,
273{
274 let a_data = a.data();
275 let b_data = b.data();
276 let mut out: Vec<T> = Vec::with_capacity(total_len);
277 let mut validity: Option<BitVec> = None;
278 for i in 0..total_len {
279 let in_then = then_mask.get(i);
280 let in_else = !in_then && else_mask.get(i);
281 let value = if in_then {
282 a_data.get(i).cloned().unwrap_or_default()
283 } else if in_else {
284 b_data.get(i).cloned().unwrap_or_default()
285 } else {
286 T::default()
287 };
288 out.push(value);
289 if !in_then && !in_else {
290 let v = validity.get_or_insert_with(|| {
291 let mut bv = BitVec::with_capacity(total_len);
292 for _ in 0..i {
293 bv.push(true);
294 }
295 bv
296 });
297 v.push(false);
298 } else if let Some(v) = validity.as_mut() {
299 v.push(true);
300 }
301 }
302 (out, validity)
303}
304
305fn uuid_scatter<T>(
306 a: &UuidContainer<T>,
307 b: &UuidContainer<T>,
308 then_mask: &BitVec,
309 else_mask: &BitVec,
310 total_len: usize,
311) -> (Vec<T>, Option<BitVec>)
312where
313 T: IsUuid + Clone + Default + Debug,
314{
315 let a_data = a.data();
316 let b_data = b.data();
317 let mut out: Vec<T> = Vec::with_capacity(total_len);
318 let mut validity: Option<BitVec> = None;
319 for i in 0..total_len {
320 let in_then = then_mask.get(i);
321 let in_else = !in_then && else_mask.get(i);
322 let value = if in_then {
323 a_data.get(i).cloned().unwrap_or_default()
324 } else if in_else {
325 b_data.get(i).cloned().unwrap_or_default()
326 } else {
327 T::default()
328 };
329 out.push(value);
330 if !in_then && !in_else {
331 let v = validity.get_or_insert_with(|| {
332 let mut bv = BitVec::with_capacity(total_len);
333 for _ in 0..i {
334 bv.push(true);
335 }
336 bv
337 });
338 v.push(false);
339 } else if let Some(v) = validity.as_mut() {
340 v.push(true);
341 }
342 }
343 (out, validity)
344}
345
346#[cfg(test)]
347mod tests {
348 use reifydb_value::{
349 util::bitvec::BitVec,
350 value::{Value, value_type::ValueType},
351 };
352
353 use crate::value::column::ColumnBuffer;
354
355 #[test]
356 fn scatter_merge_all_mapped_int4() {
357 let a = ColumnBuffer::int4([10, 20, 30, 40]);
358 let b = ColumnBuffer::int4([90, 80, 70, 60]);
359 let then_mask = BitVec::from_slice(&[true, false, true, false]);
360 let else_mask = BitVec::from_slice(&[false, true, false, true]);
361
362 let merged = a.scatter_merge(&b, &then_mask, &else_mask, 4);
363 assert!(matches!(merged, ColumnBuffer::Int4(_)));
364 assert_eq!(merged.get_value(0), Value::Int4(10));
365 assert_eq!(merged.get_value(1), Value::Int4(80));
366 assert_eq!(merged.get_value(2), Value::Int4(30));
367 assert_eq!(merged.get_value(3), Value::Int4(60));
368 }
369
370 #[test]
371 fn scatter_merge_unmapped_promotes_to_option() {
372 let a = ColumnBuffer::int4([10, 20, 30]);
373 let b = ColumnBuffer::int4([90, 80, 70]);
374 let then_mask = BitVec::from_slice(&[true, false, true]);
376 let else_mask = BitVec::from_slice(&[false, false, false]);
377
378 let merged = a.scatter_merge(&b, &then_mask, &else_mask, 3);
379 assert!(matches!(merged, ColumnBuffer::Option { .. }));
380 assert_eq!(merged.get_value(0), Value::Int4(10));
381 assert_eq!(merged.get_value(1), Value::none_of(ValueType::Int4));
382 assert_eq!(merged.get_value(2), Value::Int4(30));
383 }
384
385 #[test]
386 fn scatter_merge_bool_all_mapped() {
387 let a = ColumnBuffer::bool([true, true, false, false]);
388 let b = ColumnBuffer::bool([false, false, true, true]);
389 let then_mask = BitVec::from_slice(&[true, false, true, false]);
390 let else_mask = BitVec::from_slice(&[false, true, false, true]);
391
392 let merged = a.scatter_merge(&b, &then_mask, &else_mask, 4);
393 assert!(matches!(merged, ColumnBuffer::Bool(_)));
394 assert_eq!(merged.get_value(0), Value::Boolean(true));
395 assert_eq!(merged.get_value(1), Value::Boolean(false));
396 assert_eq!(merged.get_value(2), Value::Boolean(false));
397 assert_eq!(merged.get_value(3), Value::Boolean(true));
398 }
399
400 #[test]
401 fn scatter_merge_utf8_uses_generic_fallback() {
402 let a = ColumnBuffer::utf8(["a", "b", "c"]);
403 let b = ColumnBuffer::utf8(["x", "y", "z"]);
404 let then_mask = BitVec::from_slice(&[true, false, true]);
405 let else_mask = BitVec::from_slice(&[false, true, false]);
406
407 let merged = a.scatter_merge(&b, &then_mask, &else_mask, 3);
408 assert_eq!(merged.get_value(0), Value::Utf8("a".to_string()));
409 assert_eq!(merged.get_value(1), Value::Utf8("y".to_string()));
410 assert_eq!(merged.get_value(2), Value::Utf8("c".to_string()));
411 }
412}