(&mut self, value: impl AsRef<T::Native>)
| 337 | /// - String length exceeds `u32::MAX` |
| 338 | #[inline] |
| 339 | pub fn try_append_value(&mut self, value: impl AsRef<T::Native>) -> Result<(), ArrowError> { |
| 340 | let v: &[u8] = value.as_ref().as_ref(); |
| 341 | let length: u32 = v.len().try_into().map_err(|_| { |
| 342 | ArrowError::InvalidArgumentError(format!("String length {} exceeds u32::MAX", v.len())) |
| 343 | })?; |
| 344 | |
| 345 | if length <= MAX_INLINE_VIEW_LEN { |
| 346 | let mut view_buffer = [0; 16]; |
| 347 | view_buffer[0..4].copy_from_slice(&length.to_le_bytes()); |
| 348 | view_buffer[4..4 + v.len()].copy_from_slice(v); |
| 349 | self.views_buffer.push(u128::from_le_bytes(view_buffer)); |
| 350 | self.null_buffer_builder.append_non_null(); |
| 351 | return Ok(()); |
| 352 | } |
| 353 | |
| 354 | // Deduplication if: |
| 355 | // (1) deduplication is enabled. |
| 356 | // (2) len > `MAX_INLINE_VIEW_LEN` and len <= `max_deduplication_len` |
| 357 | let can_deduplicate = self.string_tracker.is_some() |
| 358 | && self |
| 359 | .max_deduplication_len |
| 360 | .map(|max_length| length <= max_length) |
| 361 | .unwrap_or(true); |
| 362 | if can_deduplicate { |
| 363 | if let Some((mut ht, hasher)) = self.string_tracker.take() { |
| 364 | let hash_val = hasher.hash_one(v); |
| 365 | let hasher_fn = |v: &_| hasher.hash_one(v); |
| 366 | |
| 367 | let entry = ht.entry( |
| 368 | hash_val, |
| 369 | |idx| { |
| 370 | let stored_value = self.get_value(*idx); |
| 371 | v == stored_value |
| 372 | }, |
| 373 | hasher_fn, |
| 374 | ); |
| 375 | match entry { |
| 376 | Entry::Occupied(occupied) => { |
| 377 | // If the string already exists, we will directly use the view |
| 378 | let idx = occupied.get(); |
| 379 | self.views_buffer.push(self.views_buffer[*idx]); |
| 380 | self.null_buffer_builder.append_non_null(); |
| 381 | self.string_tracker = Some((ht, hasher)); |
| 382 | return Ok(()); |
| 383 | } |
| 384 | Entry::Vacant(vacant) => { |
| 385 | // o.w. we insert the (string hash -> view index) |
| 386 | // the idx is current length of views_builder, as we are inserting a new view |
| 387 | vacant.insert(self.views_buffer.len()); |
| 388 | } |
| 389 | } |
| 390 | self.string_tracker = Some((ht, hasher)); |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | let required_cap = self.in_progress.len() + v.len(); |
| 395 | if self.in_progress.capacity() < required_cap { |
| 396 | self.flush_in_progress(); |
no test coverage detected