|
1 | 1 | // SPDX-License-Identifier: Apache-2.0 |
2 | 2 | // SPDX-FileCopyrightText: Copyright the Vortex contributors |
3 | 3 |
|
| 4 | +use std::sync::atomic::AtomicUsize; |
| 5 | +use std::sync::atomic::Ordering; |
| 6 | + |
| 7 | +use vortex_buffer::Buffer; |
4 | 8 | use vortex_error::VortexResult; |
5 | 9 | use vortex_error::vortex_bail; |
6 | 10 | use vortex_mask::Mask; |
7 | 11 |
|
| 12 | +use super::ElementTuple; |
8 | 13 | use super::element_tuple::batch_constant; |
| 14 | +use crate::ArrayRef; |
| 15 | +use crate::ExecutionCtx; |
9 | 16 | use crate::IntoArray; |
| 17 | +use crate::VortexSessionExecute; |
| 18 | +use crate::array_session; |
10 | 19 | use crate::arrays::Constant; |
11 | 20 | use crate::arrays::ConstantArray; |
12 | 21 | use crate::arrays::ExtensionArray; |
13 | 22 | use crate::arrays::MaskedArray; |
| 23 | +use crate::arrays::PrimitiveArray; |
| 24 | +use crate::dtype::DType; |
14 | 25 | use crate::dtype::Nullability; |
15 | 26 | use crate::extension::datetime::TimeUnit; |
16 | 27 | use crate::extension::datetime::Timestamp; |
| 28 | +use crate::scalar_fn::VecExecutionArgs; |
| 29 | +use crate::scalar_fn::unstable::row::InputElement; |
17 | 30 | use crate::validity::Validity; |
18 | 31 |
|
| 32 | +static DECODE_CALLS: AtomicUsize = AtomicUsize::new(0); |
| 33 | + |
| 34 | +macro_rules! i64_test_element { |
| 35 | + ($element:ident, $decode_fallible:literal $(, $can_decode:item)?) => { |
| 36 | + struct $element; |
| 37 | + |
| 38 | + // SAFETY: the view and unchecked access delegate to the `i64` implementation. |
| 39 | + unsafe impl InputElement for $element { |
| 40 | + type Column = Buffer<i64>; |
| 41 | + type View<'a> = &'a [i64]; |
| 42 | + type Elem<'a> = i64; |
| 43 | + |
| 44 | + const DENSE_SAFE: bool = true; |
| 45 | + const DECODE_FALLIBLE: bool = $decode_fallible; |
| 46 | + |
| 47 | + fn validate(dtype: &DType) -> VortexResult<()> { |
| 48 | + <i64 as InputElement>::validate(dtype) |
| 49 | + } |
| 50 | + |
| 51 | + fn decode(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self::Column> { |
| 52 | + DECODE_CALLS.fetch_add(1, Ordering::Relaxed); |
| 53 | + <i64 as InputElement>::decode(array, ctx) |
| 54 | + } |
| 55 | + |
| 56 | + $($can_decode)? |
| 57 | + |
| 58 | + fn get(column: &Self::Column, index: usize) -> i64 { |
| 59 | + <i64 as InputElement>::get(column, index) |
| 60 | + } |
| 61 | + |
| 62 | + fn view(column: &Self::Column) -> Self::View<'_> { |
| 63 | + <i64 as InputElement>::view(column) |
| 64 | + } |
| 65 | + |
| 66 | + fn view_len(view: &Self::View<'_>) -> usize { |
| 67 | + <i64 as InputElement>::view_len(view) |
| 68 | + } |
| 69 | + |
| 70 | + fn get_from_view<'a>(view: &Self::View<'a>, index: usize) -> i64 |
| 71 | + where |
| 72 | + Self: 'a, |
| 73 | + { |
| 74 | + <i64 as InputElement>::get_from_view(view, index) |
| 75 | + } |
| 76 | + |
| 77 | + unsafe fn get_from_view_unchecked<'a>(view: &Self::View<'a>, index: usize) -> i64 |
| 78 | + where |
| 79 | + Self: 'a, |
| 80 | + { |
| 81 | + // SAFETY: forwarded from this method's contract. |
| 82 | + unsafe { <i64 as InputElement>::get_from_view_unchecked(view, index) } |
| 83 | + } |
| 84 | + } |
| 85 | + }; |
| 86 | +} |
| 87 | + |
| 88 | +i64_test_element!( |
| 89 | + DecodeProbe, |
| 90 | + false, |
| 91 | + fn can_decode_null_tolerant(_array: &ArrayRef) -> VortexResult<bool> { |
| 92 | + Ok(true) |
| 93 | + } |
| 94 | +); |
| 95 | +i64_test_element!(DenseFallible, true); |
| 96 | + |
| 97 | +#[test] |
| 98 | +fn test_null_tolerant_decline_precedes_decoding() -> VortexResult<()> { |
| 99 | + DECODE_CALLS.store(0, Ordering::Relaxed); |
| 100 | + let first = PrimitiveArray::from_iter([1_i64, 2]).into_array(); |
| 101 | + let second = PrimitiveArray::from_iter([3_i64, 4]).into_array(); |
| 102 | + let args = VecExecutionArgs::new(vec![first, second], 2); |
| 103 | + let mut ctx = array_session().create_execution_ctx(); |
| 104 | + |
| 105 | + let columns = <(DecodeProbe, DenseFallible)>::decode_null_tolerant(&args, &mut ctx)?; |
| 106 | + |
| 107 | + assert!(columns.is_none()); |
| 108 | + assert_eq!(DECODE_CALLS.load(Ordering::Relaxed), 0); |
| 109 | + Ok(()) |
| 110 | +} |
| 111 | + |
19 | 112 | #[test] |
20 | 113 | fn test_batch_constant_unwraps_filtered_masked_constant() -> VortexResult<()> { |
21 | 114 | let child = ConstantArray::new(7_i64, 3).into_array(); |
|
0 commit comments