1use crate::null_sentinel;
19use arrow_array::builder::BufferBuilder;
20use arrow_array::types::ByteArrayType;
21use arrow_array::*;
22use arrow_buffer::bit_util::ceil;
23use arrow_buffer::{
24 ArrowNativeType, BooleanBuffer, MutableBuffer, NullBuffer, OffsetBuffer, ScalarBuffer,
25};
26use arrow_data::MAX_INLINE_VIEW_LEN;
27use arrow_schema::SortOptions;
28use builder::make_view;
29
30pub const BLOCK_SIZE: usize = 32;
32
33pub const MINI_BLOCK_COUNT: usize = 4;
37
38pub const MINI_BLOCK_SIZE: usize = BLOCK_SIZE / MINI_BLOCK_COUNT;
40
41pub const BLOCK_CONTINUATION: u8 = 0xFF;
43
44pub const EMPTY_SENTINEL: u8 = 1;
46
47pub const NON_EMPTY_SENTINEL: u8 = 2;
49
50pub const NULL_VALUE_SENTINEL: u8 = 3;
52
53#[inline]
55pub fn padded_length(a: Option<usize>) -> usize {
56 match a {
57 Some(a) => non_null_padded_length(a),
58 None => 1,
59 }
60}
61
62#[inline]
64pub(crate) fn non_null_padded_length(len: usize) -> usize {
65 if len <= BLOCK_SIZE {
66 1 + ceil(len, MINI_BLOCK_SIZE) * (MINI_BLOCK_SIZE + 1)
67 } else {
68 MINI_BLOCK_COUNT + ceil(len, BLOCK_SIZE) * (BLOCK_SIZE + 1)
71 }
72}
73
74pub(crate) fn decode_nulls_sentinel(rows: &[&[u8]], options: SortOptions) -> Option<NullBuffer> {
77 let null_sentinel = null_sentinel(options);
78 let nulls = BooleanBuffer::collect_bool(rows.len(), |x| rows[x][0] != null_sentinel);
79 let nulls = NullBuffer::new(nulls);
80 (nulls.null_count() > 0).then_some(nulls)
81}
82
83pub fn encode<'a, I: Iterator<Item = Option<&'a [u8]>>>(
95 data: &mut [u8],
96 offsets: &mut [usize],
97 i: I,
98 opts: SortOptions,
99) {
100 for (offset, maybe_val) in offsets.iter_mut().skip(1).zip(i) {
101 *offset += encode_one(&mut data[*offset..], maybe_val, opts);
102 }
103}
104
105pub(crate) fn encode_generic_byte_array<T: ByteArrayType>(
107 data: &mut [u8],
108 offsets: &mut [usize],
109 input_array: &GenericByteArray<T>,
110 opts: SortOptions,
111) {
112 let input_offsets = input_array.value_offsets();
113 let bytes = input_array.values().as_slice();
114
115 if let Some(null_buffer) = input_array.nulls().filter(|x| x.null_count() > 0) {
116 let input_iter =
117 input_offsets
118 .windows(2)
119 .zip(null_buffer.iter())
120 .map(|(start_end, is_valid)| {
121 if is_valid {
122 let item_range = start_end[0].as_usize()..start_end[1].as_usize();
123 let item = unsafe { bytes.get_unchecked(item_range) };
126 Some(item)
127 } else {
128 None
129 }
130 });
131
132 encode(data, offsets, input_iter, opts);
133 } else {
134 let input_iter = input_offsets.windows(2).map(|start_end| {
136 let item_range = start_end[0].as_usize()..start_end[1].as_usize();
137 let item = unsafe { bytes.get_unchecked(item_range) };
140 Some(item)
141 });
142
143 encode(data, offsets, input_iter, opts);
144 }
145}
146
147pub fn encode_null(out: &mut [u8], opts: SortOptions) -> usize {
148 out[0] = null_sentinel(opts);
149 1
150}
151
152pub fn encode_empty(out: &mut [u8], opts: SortOptions) -> usize {
153 out[0] = match opts.descending {
154 true => !EMPTY_SENTINEL,
155 false => EMPTY_SENTINEL,
156 };
157 1
158}
159
160pub fn encode_null_value(out: &mut [u8], opts: SortOptions) -> usize {
162 out[0] = match opts.descending {
163 true => !NON_EMPTY_SENTINEL,
164 false => NON_EMPTY_SENTINEL,
165 };
166 out[1] = match opts.descending {
167 true => !NULL_VALUE_SENTINEL,
168 false => NULL_VALUE_SENTINEL,
169 };
170 2
171}
172
173#[inline]
174pub fn encode_one(out: &mut [u8], val: Option<&[u8]>, opts: SortOptions) -> usize {
175 match val {
176 None => encode_null(out, opts),
177 Some([]) => encode_empty(out, opts),
178 Some(val) => {
179 out[0] = NON_EMPTY_SENTINEL;
181
182 let len = if val.len() <= BLOCK_SIZE {
183 1 + encode_blocks::<MINI_BLOCK_SIZE>(&mut out[1..], val)
184 } else {
185 let (initial, rem) = val.split_at(BLOCK_SIZE);
186 let offset = encode_blocks::<MINI_BLOCK_SIZE>(&mut out[1..], initial);
187 out[offset] = BLOCK_CONTINUATION;
188 1 + offset + encode_blocks::<BLOCK_SIZE>(&mut out[1 + offset..], rem)
189 };
190
191 if opts.descending {
192 out[..len].iter_mut().for_each(|v| *v = !*v)
194 }
195 len
196 }
197 }
198}
199
200#[inline]
202fn encode_blocks<const SIZE: usize>(out: &mut [u8], val: &[u8]) -> usize {
203 let block_count = ceil(val.len(), SIZE);
204 let end_offset = block_count * (SIZE + 1);
205 let to_write = &mut out[..end_offset];
206
207 let chunks = val.chunks_exact(SIZE);
208 let remainder = chunks.remainder();
209 for (input, output) in chunks.clone().zip(to_write.chunks_exact_mut(SIZE + 1)) {
210 let input: &[u8; SIZE] = input.try_into().unwrap();
211 let out_block: &mut [u8; SIZE] = (&mut output[..SIZE]).try_into().unwrap();
212
213 *out_block = *input;
214
215 output[SIZE] = BLOCK_CONTINUATION;
217 }
218
219 if !remainder.is_empty() {
220 let start_offset = (block_count - 1) * (SIZE + 1);
221 to_write[start_offset..start_offset + remainder.len()].copy_from_slice(remainder);
222 *to_write.last_mut().unwrap() = remainder.len() as u8;
223 } else {
224 *to_write.last_mut().unwrap() = SIZE as u8;
226 }
227 end_offset
228}
229
230pub fn decode_blocks(row: &[u8], options: SortOptions, mut f: impl FnMut(&[u8])) -> usize {
233 let (non_empty_sentinel, continuation) = match options.descending {
234 true => (!NON_EMPTY_SENTINEL, !BLOCK_CONTINUATION),
235 false => (NON_EMPTY_SENTINEL, BLOCK_CONTINUATION),
236 };
237
238 if row[0] != non_empty_sentinel {
239 return 1;
241 }
242
243 let block_len = |sentinel: u8| match options.descending {
245 true => !sentinel as usize,
246 false => sentinel as usize,
247 };
248
249 let mut idx = 1;
250 for _ in 0..MINI_BLOCK_COUNT {
251 let sentinel = row[idx + MINI_BLOCK_SIZE];
252 if sentinel != continuation {
253 f(&row[idx..idx + block_len(sentinel)]);
254 return idx + MINI_BLOCK_SIZE + 1;
255 }
256 f(&row[idx..idx + MINI_BLOCK_SIZE]);
257 idx += MINI_BLOCK_SIZE + 1;
258 }
259
260 loop {
261 let sentinel = row[idx + BLOCK_SIZE];
262 if sentinel != continuation {
263 f(&row[idx..idx + block_len(sentinel)]);
264 return idx + BLOCK_SIZE + 1;
265 }
266 f(&row[idx..idx + BLOCK_SIZE]);
267 idx += BLOCK_SIZE + 1;
268 }
269}
270
271fn decoded_len(row: &[u8], options: SortOptions) -> usize {
273 let mut len = 0;
274 decode_blocks(row, options, |block| len += block.len());
275 len
276}
277
278pub fn decode_binary<I: OffsetSizeTrait>(
280 rows: &mut [&[u8]],
281 options: SortOptions,
282) -> GenericBinaryArray<I> {
283 let len = rows.len();
284 let nulls = decode_nulls_sentinel(rows, options);
285
286 let values_capacity = rows.iter().map(|row| decoded_len(row, options)).sum();
287 let mut offsets = BufferBuilder::<I>::new(len + 1);
288 offsets.append(I::zero());
289 let mut values = MutableBuffer::new(values_capacity);
290
291 for row in rows {
292 let offset = decode_blocks(row, options, |b| values.extend_from_slice(b));
293 *row = &row[offset..];
294 offsets.append(I::from_usize(values.len()).expect("offset overflow"))
295 }
296
297 if options.descending {
298 values.as_slice_mut().iter_mut().for_each(|o| *o = !*o)
299 }
300
301 unsafe {
304 GenericBinaryArray::new_unchecked(
305 OffsetBuffer::new(ScalarBuffer::from(offsets)),
306 values.into(),
307 nulls,
308 )
309 }
310}
311
312fn decode_binary_view_inner<const VALIDATE_UTF8: bool>(
313 rows: &mut [&[u8]],
314 options: SortOptions,
315) -> BinaryViewArray {
316 let len = rows.len();
317 let inline_str_max_len = MAX_INLINE_VIEW_LEN as usize;
318
319 let nulls = decode_nulls_sentinel(rows, options);
320
321 let mut values_capacity = inline_str_max_len;
323 let mut inline_capacity = 0;
324 for row in rows.iter() {
325 let len = decoded_len(row, options);
326 if len > inline_str_max_len {
327 values_capacity += len;
328 } else if VALIDATE_UTF8 {
329 inline_capacity += len;
330 }
331 }
332 let mut values = MutableBuffer::new(values_capacity);
333 let mut view_utf8_validation_buffer = if VALIDATE_UTF8 {
334 Vec::with_capacity(inline_capacity)
335 } else {
336 Vec::new()
337 };
338
339 let mut views = vec![0_u128; len];
340 for (i, row) in rows.iter_mut().enumerate() {
341 let start_offset = values.len();
342 let offset = decode_blocks(row, options, |b| values.extend_from_slice(b));
343 let decoded_len = values.len() - start_offset;
347 if row[0] == null_sentinel(options) {
348 debug_assert_eq!(offset, 1);
349 debug_assert_eq!(start_offset, values.len());
350 } else {
351 let val = unsafe { values.get_unchecked_mut(start_offset..) };
353
354 if options.descending {
355 val.iter_mut().for_each(|o| *o = !*o);
356 }
357
358 views[i] = make_view(val, 0, start_offset as u32);
359
360 if decoded_len <= inline_str_max_len {
361 if VALIDATE_UTF8 {
362 view_utf8_validation_buffer.extend_from_slice(val);
363 }
364 values.truncate(start_offset);
365 }
366 }
367 *row = &row[offset..];
368 }
369
370 if VALIDATE_UTF8 {
371 std::str::from_utf8(&values).unwrap();
372 std::str::from_utf8(&view_utf8_validation_buffer).unwrap();
373 }
374
375 unsafe { BinaryViewArray::new_unchecked(views.into(), [values.into()], nulls) }
378}
379
380pub fn decode_binary_view(rows: &mut [&[u8]], options: SortOptions) -> BinaryViewArray {
382 decode_binary_view_inner::<false>(rows, options)
383}
384
385pub unsafe fn decode_string<I: OffsetSizeTrait>(
391 rows: &mut [&[u8]],
392 options: SortOptions,
393 validate_utf8: bool,
394) -> GenericStringArray<I> {
395 let decoded = decode_binary::<I>(rows, options);
396
397 if validate_utf8 {
398 return GenericStringArray::from(decoded);
399 }
400
401 let (offsets, values, nulls) = decoded.into_parts();
402
403 unsafe { GenericStringArray::new_unchecked(offsets, values, nulls) }
406}
407
408pub unsafe fn decode_string_view(
414 rows: &mut [&[u8]],
415 options: SortOptions,
416 validate_utf8: bool,
417) -> StringViewArray {
418 let view = if validate_utf8 {
419 decode_binary_view_inner::<true>(rows, options)
420 } else {
421 decode_binary_view_inner::<false>(rows, options)
422 };
423 unsafe { view.to_string_view_unchecked() }
424}
425
426pub fn decode_null_value(rows: &mut [&[u8]], options: SortOptions) {
427 for row in rows.iter_mut() {
428 let (sentinel1, sentinel2) = match options.descending {
429 true => (!NON_EMPTY_SENTINEL, !NULL_VALUE_SENTINEL),
430 false => (NON_EMPTY_SENTINEL, NULL_VALUE_SENTINEL),
431 };
432 debug_assert_eq!(row[0], sentinel1, "Expected NULL_VALUE_SENTINEL at byte 0");
433 debug_assert_eq!(row[1], sentinel2, "Expected NULL_VALUE_SENTINEL at byte 1");
434 *row = &row[2..];
435 }
436}