(
array: &GenericByteArray<T>,
start: T::Offset,
length: Option<T::Offset>,
)
| 250 | } |
| 251 | |
| 252 | fn byte_substring<T: ByteArrayType>( |
| 253 | array: &GenericByteArray<T>, |
| 254 | start: T::Offset, |
| 255 | length: Option<T::Offset>, |
| 256 | ) -> Result<ArrayRef, ArrowError> |
| 257 | where |
| 258 | <T as ByteArrayType>::Native: PartialEq, |
| 259 | { |
| 260 | let offsets = array.value_offsets(); |
| 261 | let data = array.value_data(); |
| 262 | let zero = <T::Offset as Zero>::zero(); |
| 263 | |
| 264 | // When array is [Large]StringArray, we will check whether `offset` is at a valid char boundary. |
| 265 | let check_char_boundary = { |
| 266 | |offset: T::Offset| { |
| 267 | if !matches!(T::DATA_TYPE, DataType::Utf8 | DataType::LargeUtf8) { |
| 268 | return Ok(offset); |
| 269 | } |
| 270 | // Safety: a StringArray must contain valid UTF8 data |
| 271 | let data_str = unsafe { std::str::from_utf8_unchecked(data) }; |
| 272 | let offset_usize = offset.as_usize(); |
| 273 | if data_str.is_char_boundary(offset_usize) { |
| 274 | Ok(offset) |
| 275 | } else { |
| 276 | Err(ArrowError::ComputeError(format!( |
| 277 | "The offset {offset_usize} is at an invalid utf-8 boundary." |
| 278 | ))) |
| 279 | } |
| 280 | } |
| 281 | }; |
| 282 | |
| 283 | // start and end offsets of all substrings |
| 284 | let mut new_starts_ends: Vec<(T::Offset, T::Offset)> = Vec::with_capacity(array.len()); |
| 285 | let mut new_offsets: Vec<T::Offset> = Vec::with_capacity(array.len() + 1); |
| 286 | let mut len_so_far = zero; |
| 287 | new_offsets.push(zero); |
| 288 | |
| 289 | offsets |
| 290 | .windows(2) |
| 291 | .try_for_each(|pair| -> Result<(), ArrowError> { |
| 292 | let new_start = match start.cmp(&zero) { |
| 293 | Ordering::Greater => check_char_boundary((pair[0] + start).min(pair[1]))?, |
| 294 | Ordering::Equal => pair[0], |
| 295 | Ordering::Less => check_char_boundary((pair[1] + start).max(pair[0]))?, |
| 296 | }; |
| 297 | let new_end = match length { |
| 298 | Some(length) => check_char_boundary((length + new_start).min(pair[1]))?, |
| 299 | None => pair[1], |
| 300 | }; |
| 301 | len_so_far += new_end - new_start; |
| 302 | new_starts_ends.push((new_start, new_end)); |
| 303 | new_offsets.push(len_so_far); |
| 304 | Ok(()) |
| 305 | })?; |
| 306 | |
| 307 | // concatenate substrings into a buffer |
| 308 | let mut new_values = MutableBuffer::new(new_offsets.last().unwrap().as_usize()); |
| 309 |
no test coverage detected