Path: blob/main/crates/polars-arrow/src/array/binview/mutable.rs
6939 views
use std::any::Any;1use std::fmt::{Debug, Formatter};2use std::ops::Deref;3use std::sync::Arc;45use hashbrown::hash_map::Entry;6use polars_error::PolarsResult;7use polars_utils::aliases::{InitHashMaps, PlHashMap};89use crate::array::binview::iterator::MutableBinaryViewValueIter;10use crate::array::binview::view::validate_views_utf8_only;11use crate::array::binview::{12BinaryViewArrayGeneric, DEFAULT_BLOCK_SIZE, MAX_EXP_BLOCK_SIZE, ViewType,13};14use crate::array::{Array, MutableArray, TryExtend, TryPush, View};15use crate::bitmap::MutableBitmap;16use crate::buffer::Buffer;17use crate::datatypes::ArrowDataType;18use crate::legacy::trusted_len::TrustedLenPush;19use crate::trusted_len::TrustedLen;2021// Invariants:22//23// - Each view must point to a valid slice of a buffer24// - `total_buffer_len` must be equal to `completed_buffers.iter().map(Vec::len).sum()`25// - `total_bytes_len` must be equal to `views.iter().map(View::len).sum()`26pub struct MutableBinaryViewArray<T: ViewType + ?Sized> {27pub(crate) views: Vec<View>,28pub(crate) completed_buffers: Vec<Buffer<u8>>,29pub(crate) in_progress_buffer: Vec<u8>,30pub(crate) validity: Option<MutableBitmap>,31pub(crate) phantom: std::marker::PhantomData<T>,32/// Total bytes length if we would concatenate them all.33pub(crate) total_bytes_len: usize,34/// Total bytes in the buffer (excluding remaining capacity)35pub(crate) total_buffer_len: usize,36/// Mapping from `Buffer::deref()` to index in `completed_buffers`.37/// Used in `push_view()`.38pub(crate) stolen_buffers: PlHashMap<usize, u32>,39}4041impl<T: ViewType + ?Sized> Clone for MutableBinaryViewArray<T> {42fn clone(&self) -> Self {43Self {44views: self.views.clone(),45completed_buffers: self.completed_buffers.clone(),46in_progress_buffer: self.in_progress_buffer.clone(),47validity: self.validity.clone(),48phantom: Default::default(),49total_bytes_len: self.total_bytes_len,50total_buffer_len: self.total_buffer_len,51stolen_buffers: PlHashMap::new(),52}53}54}5556impl<T: ViewType + ?Sized> Debug for MutableBinaryViewArray<T> {57fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {58write!(f, "mutable-binview{:?}", T::DATA_TYPE)59}60}6162impl<T: ViewType + ?Sized> Default for MutableBinaryViewArray<T> {63fn default() -> Self {64Self::with_capacity(0)65}66}6768impl<T: ViewType + ?Sized> From<MutableBinaryViewArray<T>> for BinaryViewArrayGeneric<T> {69fn from(mut value: MutableBinaryViewArray<T>) -> Self {70value.finish_in_progress();71unsafe {72Self::new_unchecked(73T::DATA_TYPE,74value.views.into(),75Arc::from(value.completed_buffers),76value.validity.map(|b| b.into()),77value.total_bytes_len,78value.total_buffer_len,79)80}81}82}8384impl<T: ViewType + ?Sized> MutableBinaryViewArray<T> {85pub fn new() -> Self {86Self::default()87}8889pub fn with_capacity(capacity: usize) -> Self {90Self {91views: Vec::with_capacity(capacity),92completed_buffers: vec![],93in_progress_buffer: vec![],94validity: None,95phantom: Default::default(),96total_buffer_len: 0,97total_bytes_len: 0,98stolen_buffers: PlHashMap::new(),99}100}101102/// Get a mutable reference to the [`Vec`] of [`View`]s in this [`MutableBinaryViewArray`].103///104/// # Safety105///106/// This is safe as long as any mutation of the [`Vec`] does not break any invariants of the107/// [`MutableBinaryViewArray`] before it is read again.108#[inline]109pub unsafe fn views_mut(&mut self) -> &mut Vec<View> {110&mut self.views111}112113/// Set the `total_bytes_len` of the [`MutableBinaryViewArray`]114///115/// # Safety116///117/// This should not break invariants of the [`MutableBinaryViewArray`]118#[inline]119pub unsafe fn set_total_bytes_len(&mut self, value: usize) {120#[cfg(debug_assertions)]121{122let actual_length: usize = self.views().iter().map(|v| v.length as usize).sum();123assert_eq!(value, actual_length);124}125126self.total_bytes_len = value;127}128129pub fn total_bytes_len(&self) -> usize {130self.total_bytes_len131}132133pub fn total_buffer_len(&self) -> usize {134self.total_buffer_len135}136137#[inline]138pub fn views(&self) -> &[View] {139&self.views140}141142#[inline]143pub fn completed_buffers(&self) -> &[Buffer<u8>] {144&self.completed_buffers145}146147pub fn validity(&mut self) -> Option<&mut MutableBitmap> {148self.validity.as_mut()149}150151/// Reserves `additional` elements and `additional_buffer` on the buffer.152pub fn reserve(&mut self, additional: usize) {153self.views.reserve(additional);154}155156#[inline]157pub fn len(&self) -> usize {158self.views.len()159}160161#[inline]162pub fn capacity(&self) -> usize {163self.views.capacity()164}165166fn init_validity(&mut self, unset_last: bool) {167let mut validity = MutableBitmap::with_capacity(self.views.capacity());168validity.extend_constant(self.len(), true);169if unset_last {170validity.set(self.len() - 1, false);171}172self.validity = Some(validity);173}174175/// # Safety176/// - caller must allocate enough capacity177/// - caller must ensure the view and buffers match.178/// - The array must not have validity.179pub(crate) unsafe fn push_view_unchecked(&mut self, v: View, buffers: &[Buffer<u8>]) {180let len = v.length;181self.total_bytes_len += len as usize;182if len <= 12 {183debug_assert!(self.views.capacity() > self.views.len());184self.views.push_unchecked(v)185} else {186self.total_buffer_len += len as usize;187let data = buffers.get_unchecked(v.buffer_idx as usize);188let offset = v.offset as usize;189let bytes = data.get_unchecked(offset..offset + len as usize);190let t = T::from_bytes_unchecked(bytes);191self.push_value_ignore_validity(t)192}193}194195/// # Safety196/// - caller must allocate enough capacity197/// - caller must ensure the view and buffers match.198/// - The array must not have validity.199/// - caller must not mix use this function with other push functions.200pub unsafe fn push_view_unchecked_dedupe(&mut self, mut v: View, buffers: &[Buffer<u8>]) {201let len = v.length;202self.total_bytes_len += len as usize;203if len <= 12 {204self.views.push_unchecked(v);205} else {206let buffer = buffers.get_unchecked(v.buffer_idx as usize);207let idx = match self.stolen_buffers.entry(buffer.deref().as_ptr() as usize) {208Entry::Occupied(entry) => *entry.get(),209Entry::Vacant(entry) => {210let idx = self.completed_buffers.len() as u32;211entry.insert(idx);212self.completed_buffers.push(buffer.clone());213self.total_buffer_len += buffer.len();214idx215},216};217v.buffer_idx = idx;218self.views.push_unchecked(v);219}220}221222pub fn push_view(&mut self, mut v: View, buffers: &[Buffer<u8>]) {223let len = v.length;224self.total_bytes_len += len as usize;225if len <= 12 {226self.views.push(v);227} else {228// Do no mix use of push_view and push_value_ignore_validity -229// it causes fragmentation.230self.finish_in_progress();231232let buffer = &buffers[v.buffer_idx as usize];233let idx = match self.stolen_buffers.entry(buffer.deref().as_ptr() as usize) {234Entry::Occupied(entry) => {235let idx = *entry.get();236let target_buffer = &self.completed_buffers[idx as usize];237debug_assert_eq!(buffer, target_buffer);238idx239},240Entry::Vacant(entry) => {241let idx = self.completed_buffers.len() as u32;242entry.insert(idx);243self.completed_buffers.push(buffer.clone());244self.total_buffer_len += buffer.len();245idx246},247};248v.buffer_idx = idx;249self.views.push(v);250}251if let Some(validity) = &mut self.validity {252validity.push(true)253}254}255256#[inline]257pub fn push_value_ignore_validity<V: AsRef<T>>(&mut self, value: V) {258let bytes = value.as_ref().to_bytes();259self.total_bytes_len += bytes.len();260let view = self.push_value_into_buffer(bytes);261self.views.push(view);262}263264#[inline]265pub fn push_buffer(&mut self, buffer: Buffer<u8>) -> u32 {266self.finish_in_progress();267268let buffer_idx = self.completed_buffers.len();269self.total_buffer_len += buffer.len();270self.completed_buffers.push(buffer);271buffer_idx as u32272}273274#[inline]275pub fn push_value<V: AsRef<T>>(&mut self, value: V) {276if let Some(validity) = &mut self.validity {277validity.push(true)278}279self.push_value_ignore_validity(value)280}281282#[inline]283pub fn push<V: AsRef<T>>(&mut self, value: Option<V>) {284if let Some(value) = value {285self.push_value(value)286} else {287self.push_null()288}289}290291#[inline]292pub fn push_null(&mut self) {293self.views.push(View::default());294match &mut self.validity {295Some(validity) => validity.push(false),296None => self.init_validity(true),297}298}299300/// Get a [`View`] for a specific set of bytes.301pub fn push_value_into_buffer(&mut self, bytes: &[u8]) -> View {302assert!(bytes.len() <= u32::MAX as usize);303304if bytes.len() <= View::MAX_INLINE_SIZE as usize {305View::new_inline(bytes)306} else {307self.total_buffer_len += bytes.len();308309// We want to make sure that we never have to memcopy between buffers. So if the310// current buffer is not large enough, create a new buffer that is large enough and try311// to anticipate the larger size.312let required_capacity = self.in_progress_buffer.len() + bytes.len();313let does_not_fit_in_buffer = self.in_progress_buffer.capacity() < required_capacity;314315// We can only save offsets that are below u32::MAX316let offset_will_not_fit = self.in_progress_buffer.len() > u32::MAX as usize;317318if does_not_fit_in_buffer || offset_will_not_fit {319// Allocate a new buffer and flush the old buffer320let new_capacity = (self.in_progress_buffer.capacity() * 2)321.clamp(DEFAULT_BLOCK_SIZE, MAX_EXP_BLOCK_SIZE)322.max(bytes.len());323let in_progress = Vec::with_capacity(new_capacity);324let flushed = std::mem::replace(&mut self.in_progress_buffer, in_progress);325if !flushed.is_empty() {326self.completed_buffers.push(flushed.into())327}328}329330let offset = self.in_progress_buffer.len() as u32;331self.in_progress_buffer.extend_from_slice(bytes);332333let buffer_idx = u32::try_from(self.completed_buffers.len()).unwrap();334335View::new_from_bytes(bytes, buffer_idx, offset)336}337}338339pub fn extend_null(&mut self, additional: usize) {340if self.validity.is_none() && additional > 0 {341self.init_validity(false);342}343self.views344.extend(std::iter::repeat_n(View::default(), additional));345if let Some(validity) = &mut self.validity {346validity.extend_constant(additional, false);347}348}349350pub fn extend_constant<V: AsRef<T>>(&mut self, additional: usize, value: Option<V>) {351if value.is_none() && self.validity.is_none() {352self.init_validity(false);353}354355if let Some(validity) = &mut self.validity {356validity.extend_constant(additional, value.is_some())357}358359// Push and pop to get the properly encoded value.360// For long string this leads to a dictionary encoding,361// as we push the string only once in the buffers362let view_value = value363.map(|v| {364self.push_value_ignore_validity(v);365self.views.pop().unwrap()366})367.unwrap_or_default();368self.views369.extend(std::iter::repeat_n(view_value, additional));370}371372impl_mutable_array_mut_validity!();373374#[inline]375pub fn extend_values<I, P>(&mut self, iterator: I)376where377I: Iterator<Item = P>,378P: AsRef<T>,379{380self.reserve(iterator.size_hint().0);381for v in iterator {382self.push_value(v)383}384}385386#[inline]387pub fn extend_trusted_len_values<I, P>(&mut self, iterator: I)388where389I: TrustedLen<Item = P>,390P: AsRef<T>,391{392self.extend_values(iterator)393}394395#[inline]396pub fn extend<I, P>(&mut self, iterator: I)397where398I: Iterator<Item = Option<P>>,399P: AsRef<T>,400{401self.reserve(iterator.size_hint().0);402for p in iterator {403self.push(p)404}405}406407#[inline]408pub fn extend_trusted_len<I, P>(&mut self, iterator: I)409where410I: TrustedLen<Item = Option<P>>,411P: AsRef<T>,412{413self.extend(iterator)414}415416#[inline]417pub fn extend_views<I>(&mut self, iterator: I, buffers: &[Buffer<u8>])418where419I: Iterator<Item = Option<View>>,420{421self.reserve(iterator.size_hint().0);422for p in iterator {423match p {424Some(v) => self.push_view(v, buffers),425None => self.push_null(),426}427}428}429430#[inline]431pub fn extend_views_trusted_len<I>(&mut self, iterator: I, buffers: &[Buffer<u8>])432where433I: TrustedLen<Item = Option<View>>,434{435self.extend_views(iterator, buffers);436}437438#[inline]439pub fn extend_non_null_views<I>(&mut self, iterator: I, buffers: &[Buffer<u8>])440where441I: Iterator<Item = View>,442{443self.reserve(iterator.size_hint().0);444for v in iterator {445self.push_view(v, buffers);446}447}448449#[inline]450pub fn extend_non_null_views_trusted_len<I>(&mut self, iterator: I, buffers: &[Buffer<u8>])451where452I: TrustedLen<Item = View>,453{454self.extend_non_null_views(iterator, buffers);455}456457/// # Safety458/// Same as `push_view_unchecked()`.459#[inline]460pub unsafe fn extend_non_null_views_unchecked<I>(&mut self, iterator: I, buffers: &[Buffer<u8>])461where462I: Iterator<Item = View>,463{464self.reserve(iterator.size_hint().0);465for v in iterator {466self.push_view_unchecked(v, buffers);467}468}469470/// # Safety471/// Same as `push_view_unchecked()`.472#[inline]473pub unsafe fn extend_non_null_views_unchecked_dedupe<I>(474&mut self,475iterator: I,476buffers: &[Buffer<u8>],477) where478I: Iterator<Item = View>,479{480self.reserve(iterator.size_hint().0);481for v in iterator {482self.push_view_unchecked_dedupe(v, buffers);483}484}485486#[inline]487pub fn from_iterator<I, P>(iterator: I) -> Self488where489I: Iterator<Item = Option<P>>,490P: AsRef<T>,491{492let mut mutable = Self::with_capacity(iterator.size_hint().0);493mutable.extend(iterator);494mutable495}496497pub fn from_values_iter<I, P>(iterator: I) -> Self498where499I: Iterator<Item = P>,500P: AsRef<T>,501{502let mut mutable = Self::with_capacity(iterator.size_hint().0);503mutable.extend_values(iterator);504mutable505}506507pub fn from<S: AsRef<T>, P: AsRef<[Option<S>]>>(slice: P) -> Self {508Self::from_iterator(slice.as_ref().iter().map(|opt_v| opt_v.as_ref()))509}510511pub fn finish_in_progress(&mut self) -> bool {512if !self.in_progress_buffer.is_empty() {513self.completed_buffers514.push(std::mem::take(&mut self.in_progress_buffer).into());515true516} else {517false518}519}520521#[inline]522pub fn freeze(self) -> BinaryViewArrayGeneric<T> {523self.into()524}525526#[inline]527pub fn freeze_with_dtype(self, dtype: ArrowDataType) -> BinaryViewArrayGeneric<T> {528let mut arr: BinaryViewArrayGeneric<T> = self.into();529arr.dtype = dtype;530arr531}532533pub fn take(self) -> (Vec<View>, Vec<Buffer<u8>>) {534(self.views, self.completed_buffers)535}536537#[inline]538pub fn value(&self, i: usize) -> &T {539assert!(i < self.len());540unsafe { self.value_unchecked(i) }541}542543/// Returns the element at index `i`544///545/// # Safety546/// Assumes that the `i < self.len`.547#[inline]548pub unsafe fn value_unchecked(&self, i: usize) -> &T {549self.value_from_view_unchecked(self.views.get_unchecked(i))550}551552/// Returns the element indicated by the given view.553///554/// # Safety555/// Assumes the View belongs to this MutableBinaryViewArray.556pub unsafe fn value_from_view_unchecked<'a>(&'a self, view: &'a View) -> &'a T {557// View layout:558// length: 4 bytes559// prefix: 4 bytes560// buffer_index: 4 bytes561// offset: 4 bytes562563// Inlined layout:564// length: 4 bytes565// data: 12 bytes566let len = view.length;567let bytes = if len <= 12 {568let ptr = view as *const View as *const u8;569std::slice::from_raw_parts(ptr.add(4), len as usize)570} else {571let buffer_idx = view.buffer_idx as usize;572let offset = view.offset;573574let data = if buffer_idx == self.completed_buffers.len() {575self.in_progress_buffer.as_slice()576} else {577self.completed_buffers.get_unchecked(buffer_idx)578};579580let offset = offset as usize;581data.get_unchecked(offset..offset + len as usize)582};583T::from_bytes_unchecked(bytes)584}585586/// Returns an iterator of `&[u8]` over every element of this array, ignoring the validity587pub fn values_iter(&self) -> MutableBinaryViewValueIter<'_, T> {588MutableBinaryViewValueIter::new(self)589}590591pub fn extend_from_array(&mut self, other: &BinaryViewArrayGeneric<T>) {592let slf_len = self.len();593match (&mut self.validity, other.validity()) {594(None, None) => {},595(Some(v), None) => v.extend_constant(other.len(), true),596(v @ None, Some(other)) => {597let mut bm = MutableBitmap::with_capacity(slf_len + other.len());598bm.extend_constant(slf_len, true);599bm.extend_from_bitmap(other);600*v = Some(bm);601},602(Some(slf), Some(other)) => slf.extend_from_bitmap(other),603}604605if other.total_buffer_len() == 0 {606self.views.extend(other.views().iter().copied());607} else {608self.finish_in_progress();609610let buffer_offset = self.completed_buffers().len() as u32;611self.completed_buffers612.extend(other.data_buffers().iter().cloned());613614self.views.extend(other.views().iter().map(|view| {615let mut view = *view;616if view.length > View::MAX_INLINE_SIZE {617view.buffer_idx += buffer_offset;618}619view620}));621622let new_total_buffer_len = self.total_buffer_len() + other.total_buffer_len();623self.total_buffer_len = new_total_buffer_len;624}625626self.total_bytes_len = self.total_bytes_len() + other.total_bytes_len();627}628}629630impl MutableBinaryViewArray<[u8]> {631pub fn validate_utf8(&mut self, buffer_offset: usize, views_offset: usize) -> PolarsResult<()> {632// Finish the in progress as it might be required for validation.633let pushed = self.finish_in_progress();634// views are correct635unsafe {636validate_views_utf8_only(637&self.views[views_offset..],638&self.completed_buffers,639buffer_offset,640)?641}642// Restore in-progress buffer as we don't want to get too small buffers643if pushed {644if let Some(last) = self.completed_buffers.pop() {645self.in_progress_buffer = last.into_mut().right().unwrap();646}647}648Ok(())649}650651/// Extend from a `buffer` and `length` of items given some statistics about the lengths.652///653/// This will attempt to dispatch to several optimized implementations.654///655/// # Safety656///657/// This is safe if the statistics are correct.658pub unsafe fn extend_from_lengths_with_stats(659&mut self,660buffer: &[u8],661lengths_iterator: impl Clone + ExactSizeIterator<Item = usize>,662min_length: usize,663max_length: usize,664sum_length: usize,665) {666let num_items = lengths_iterator.len();667668if num_items == 0 {669return;670}671672#[cfg(debug_assertions)]673{674let (min, max, sum) = lengths_iterator.clone().map(|v| (v, v, v)).fold(675(usize::MAX, usize::MIN, 0usize),676|(cmin, cmax, csum), (emin, emax, esum)| {677(cmin.min(emin), cmax.max(emax), csum + esum)678},679);680681assert_eq!(min, min_length);682assert_eq!(max, max_length);683assert_eq!(sum, sum_length);684}685686assert!(sum_length <= buffer.len());687688let mut buffer_offset = 0;689if min_length > View::MAX_INLINE_SIZE as usize690&& (num_items == 1 || sum_length + self.in_progress_buffer.len() <= u32::MAX as usize)691{692let buffer_idx = self.completed_buffers().len() as u32;693let in_progress_buffer_offset = self.in_progress_buffer.len();694695self.total_bytes_len += sum_length;696self.total_buffer_len += sum_length;697698self.in_progress_buffer699.extend_from_slice(&buffer[..sum_length]);700self.views.extend(lengths_iterator.map(|length| {701// SAFETY: We asserted before that the sum of all lengths is smaller or equal to702// the buffer length.703let view_buffer =704unsafe { buffer.get_unchecked(buffer_offset..buffer_offset + length) };705706// SAFETY: We know that the minimum length > View::MAX_INLINE_SIZE. Therefore, this707// length is > View::MAX_INLINE_SIZE.708let view = unsafe {709View::new_noninline_unchecked(710view_buffer,711buffer_idx,712(buffer_offset + in_progress_buffer_offset) as u32,713)714};715buffer_offset += length;716view717}));718} else if max_length <= View::MAX_INLINE_SIZE as usize {719self.total_bytes_len += sum_length;720721// If the min and max are the same, we can dispatch to the optimized SIMD722// implementation.723if min_length == max_length {724let length = min_length;725if length == 0 {726self.views727.resize(self.views.len() + num_items, View::new_inline(&[]));728} else {729View::extend_with_inlinable_strided(730&mut self.views,731&buffer[..length * num_items],732length as u8,733);734}735} else {736self.views.extend(lengths_iterator.map(|length| {737// SAFETY: We asserted before that the sum of all lengths is smaller or equal738// to the buffer length.739let view_buffer =740unsafe { buffer.get_unchecked(buffer_offset..buffer_offset + length) };741742// SAFETY: We know that each view has a length <= View::MAX_INLINE_SIZE because743// the maximum length is <= View::MAX_INLINE_SIZE744let view = unsafe { View::new_inline_unchecked(view_buffer) };745746buffer_offset += length;747748view749}));750}751} else {752// If all fails, just fall back to a base implementation.753self.reserve(num_items);754for length in lengths_iterator {755let value = &buffer[buffer_offset..buffer_offset + length];756buffer_offset += length;757self.push_value(value);758}759}760}761762/// Extend from a `buffer` and `length` of items.763///764/// This will attempt to dispatch to several optimized implementations.765#[inline]766pub fn extend_from_lengths(767&mut self,768buffer: &[u8],769lengths_iterator: impl Clone + ExactSizeIterator<Item = usize>,770) {771let (min, max, sum) = lengths_iterator.clone().map(|v| (v, v, v)).fold(772(usize::MAX, usize::MIN, 0usize),773|(cmin, cmax, csum), (emin, emax, esum)| (cmin.min(emin), cmax.max(emax), csum + esum),774);775776// SAFETY: We just collected the right stats.777unsafe { self.extend_from_lengths_with_stats(buffer, lengths_iterator, min, max, sum) }778}779}780781impl<T: ViewType + ?Sized, P: AsRef<T>> Extend<Option<P>> for MutableBinaryViewArray<T> {782#[inline]783fn extend<I: IntoIterator<Item = Option<P>>>(&mut self, iter: I) {784Self::extend(self, iter.into_iter())785}786}787788impl<T: ViewType + ?Sized, P: AsRef<T>> FromIterator<Option<P>> for MutableBinaryViewArray<T> {789#[inline]790fn from_iter<I: IntoIterator<Item = Option<P>>>(iter: I) -> Self {791Self::from_iterator(iter.into_iter())792}793}794795impl<T: ViewType + ?Sized> MutableArray for MutableBinaryViewArray<T> {796fn dtype(&self) -> &ArrowDataType {797T::dtype()798}799800fn len(&self) -> usize {801MutableBinaryViewArray::len(self)802}803804fn validity(&self) -> Option<&MutableBitmap> {805self.validity.as_ref()806}807808fn as_box(&mut self) -> Box<dyn Array> {809let mutable = std::mem::take(self);810let arr: BinaryViewArrayGeneric<T> = mutable.into();811arr.boxed()812}813814fn as_any(&self) -> &dyn Any {815self816}817818fn as_mut_any(&mut self) -> &mut dyn Any {819self820}821822fn push_null(&mut self) {823MutableBinaryViewArray::push_null(self)824}825826fn reserve(&mut self, additional: usize) {827MutableBinaryViewArray::reserve(self, additional)828}829830fn shrink_to_fit(&mut self) {831self.views.shrink_to_fit()832}833}834835impl<T: ViewType + ?Sized, P: AsRef<T>> TryExtend<Option<P>> for MutableBinaryViewArray<T> {836/// This is infallible and is implemented for consistency with all other types837#[inline]838fn try_extend<I: IntoIterator<Item = Option<P>>>(&mut self, iter: I) -> PolarsResult<()> {839self.extend(iter.into_iter());840Ok(())841}842}843844impl<T: ViewType + ?Sized, P: AsRef<T>> TryPush<Option<P>> for MutableBinaryViewArray<T> {845/// This is infallible and is implemented for consistency with all other types846#[inline(always)]847fn try_push(&mut self, item: Option<P>) -> PolarsResult<()> {848self.push(item.as_ref().map(|p| p.as_ref()));849Ok(())850}851}852853#[cfg(test)]854mod tests {855use super::*;856857fn roundtrip(values: &[&[u8]]) -> bool {858let buffer = values859.iter()860.flat_map(|v| v.iter().copied())861.collect::<Vec<u8>>();862let lengths = values.iter().map(|v| v.len()).collect::<Vec<usize>>();863let mut bv = MutableBinaryViewArray::<[u8]>::with_capacity(values.len());864865bv.extend_from_lengths(&buffer[..], lengths.into_iter());866867&bv.values_iter().collect::<Vec<&[u8]>>()[..] == values868}869870#[test]871fn extend_with_lengths_basic() {872assert!(roundtrip(&[]));873assert!(roundtrip(&[b"abc"]));874assert!(roundtrip(&[875b"a_very_very_long_string_that_is_not_inlinable"876]));877assert!(roundtrip(&[878b"abc",879b"a_very_very_long_string_that_is_not_inlinable"880]));881}882883#[test]884fn extend_with_inlinable_fastpath() {885assert!(roundtrip(&[b"abc", b"defg", b"hix"]));886assert!(roundtrip(&[b"abc", b"defg", b"hix", b"xyza1234abcd"]));887}888889#[test]890fn extend_with_inlinable_eq_len_fastpath() {891assert!(roundtrip(&[b"abc", b"def", b"hix"]));892assert!(roundtrip(&[b"abc", b"def", b"hix", b"xyz"]));893}894895#[test]896fn extend_with_not_inlinable_fastpath() {897assert!(roundtrip(&[898b"a_very_long_string123",899b"a_longer_string_than_the_previous"900]));901}902}903904905