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