arrow_data/equal/
variable_size.rs1use super::utils::equal_len;
6use crate::data::{ArrayData, contains_nulls};
7use crate::equal::list::lengths_equal;
8use arrow_buffer::ArrowNativeType;
9use num_integer::Integer;
10
11fn offset_value_equal<T: ArrowNativeType + Integer>(
12 lhs_values: &[u8],
13 rhs_values: &[u8],
14 lhs_offsets: &[T],
15 rhs_offsets: &[T],
16 lhs_pos: usize,
17 rhs_pos: usize,
18 len: usize,
19) -> bool {
20 let lhs_start = lhs_offsets[lhs_pos].as_usize();
21 let rhs_start = rhs_offsets[rhs_pos].as_usize();
22 let lhs_len = (lhs_offsets[lhs_pos + len] - lhs_offsets[lhs_pos])
23 .to_usize()
24 .unwrap();
25 let rhs_len = (rhs_offsets[rhs_pos + len] - rhs_offsets[rhs_pos])
26 .to_usize()
27 .unwrap();
28
29 if lhs_len == 0 && rhs_len == 0 {
30 return true;
31 }
32
33 lhs_len == rhs_len && equal_len(lhs_values, rhs_values, lhs_start, rhs_start, lhs_len)
34}
35
36pub(super) fn variable_sized_equal<T: ArrowNativeType + Integer>(
37 lhs: &ArrayData,
38 rhs: &ArrayData,
39 lhs_start: usize,
40 rhs_start: usize,
41 len: usize,
42) -> bool {
43 let lhs_offsets = lhs.buffer::<T>(0);
44 let rhs_offsets = rhs.buffer::<T>(0);
45
46 let lhs_values = lhs.buffers()[1].as_slice();
48 let rhs_values = rhs.buffers()[1].as_slice();
49
50 if !contains_nulls(lhs.nulls(), lhs_start, len) {
53 let lhs_offsets_slice = &lhs_offsets[lhs_start..lhs_start + len + 1];
54 let rhs_offsets_slice = &rhs_offsets[rhs_start..rhs_start + len + 1];
55 lengths_equal(lhs_offsets_slice, rhs_offsets_slice)
56 && offset_value_equal(
57 lhs_values,
58 rhs_values,
59 lhs_offsets,
60 rhs_offsets,
61 lhs_start,
62 rhs_start,
63 len,
64 )
65 } else {
66 (0..len).all(|i| {
67 let lhs_pos = lhs_start + i;
68 let rhs_pos = rhs_start + i;
69
70 let lhs_is_null = lhs.nulls().is_some_and(|v| v.is_null(lhs_pos));
72 let rhs_is_null = rhs.nulls().is_some_and(|v| v.is_null(rhs_pos));
73
74 lhs_is_null
75 || (lhs_is_null == rhs_is_null)
76 && offset_value_equal(
77 lhs_values,
78 rhs_values,
79 lhs_offsets,
80 rhs_offsets,
81 lhs_pos,
82 rhs_pos,
83 1,
84 )
85 })
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::ArrayData;
92 use crate::equal::variable_size::variable_sized_equal;
93 use arrow_buffer::Buffer;
94 use arrow_schema::DataType;
95
96 #[test]
97 fn test_variable_sized_equal_diff_offsets() {
98 let a = ArrayData::builder(DataType::Utf8)
99 .buffers(vec![
100 Buffer::from_vec(vec![0_i32, 3, 6]),
101 Buffer::from_slice_ref(b"foobar"),
102 ])
103 .null_bit_buffer(Some(Buffer::from_slice_ref([0b01_u8])))
104 .len(2)
105 .build()
106 .unwrap();
107 let b = ArrayData::builder(DataType::Utf8)
108 .buffers(vec![
109 Buffer::from_vec(vec![0_i32, 2, 6]),
110 Buffer::from_slice_ref(b"foobar"),
111 ])
112 .null_bit_buffer(Some(Buffer::from_slice_ref([0b01_u8])))
113 .len(2)
114 .build()
115 .unwrap();
116
117 assert!(!variable_sized_equal::<i32>(&a, &b, 0, 0, 2));
118 }
119}