polars_arrow/array/binview/
builder.rs1use std::marker::PhantomData;
2use std::sync::LazyLock;
3
4use hashbrown::hash_map::Entry;
5use polars_buffer::Buffer;
6use polars_utils::IdxSize;
7use polars_utils::aliases::{InitHashMaps, PlHashMap};
8
9use crate::array::binview::{
10 BINVIEW_ARROW_BUFFER_LEN_LIMIT, DEFAULT_BLOCK_SIZE, MAX_EXP_BLOCK_SIZE,
11};
12use crate::array::builder::{ShareStrategy, StaticArrayBuilder};
13use crate::array::{Array, BINVIEW_MAX_ROW_BYTE_LEN, BinaryViewArrayGeneric, View, ViewType};
14use crate::bitmap::OptBitmapBuilder;
15use crate::datatypes::ArrowDataType;
16use crate::pushable::Pushable;
17
18static PLACEHOLDER_BUFFER: LazyLock<Buffer<u8>> = LazyLock::new(|| Buffer::from_static(&[]));
19
20pub struct BinaryViewArrayGenericBuilder<V: ViewType + ?Sized> {
21 dtype: ArrowDataType,
22 views: Vec<View>,
23 active_buffer: Vec<u8>,
24 active_buffer_idx: u32,
25 buffer_set: Vec<Buffer<u8>>,
26 stolen_buffers: PlHashMap<usize, u32>,
27
28 last_buffer_set_stolen_from: Option<Buffer<Buffer<u8>>>,
31 buffer_set_translation_idxs: Vec<(u32, u32)>, buffer_set_translation_generation: u32,
33
34 validity: OptBitmapBuilder,
35 total_bytes_len: usize,
37 total_buffer_len: usize,
39 view_type: PhantomData<V>,
40}
41
42impl<V: ViewType + ?Sized> BinaryViewArrayGenericBuilder<V> {
43 pub fn new(dtype: ArrowDataType) -> Self {
44 Self {
45 dtype,
46 views: Vec::new(),
47 active_buffer: Vec::new(),
48 active_buffer_idx: 0,
49 buffer_set: Vec::new(),
50 stolen_buffers: PlHashMap::new(),
51 last_buffer_set_stolen_from: None,
52 buffer_set_translation_idxs: Vec::new(),
53 buffer_set_translation_generation: 0,
54 validity: OptBitmapBuilder::default(),
55 total_bytes_len: 0,
56 total_buffer_len: 0,
57 view_type: PhantomData,
58 }
59 }
60
61 #[inline]
62 fn reserve_active_buffer(&mut self, additional: usize) {
63 let len = self.active_buffer.len();
64 let cap = self.active_buffer.capacity();
65 if len.saturating_add(additional) > usize::min(BINVIEW_ARROW_BUFFER_LEN_LIMIT, cap) {
66 self.reserve_active_buffer_slow(additional);
67 }
68 }
69
70 #[cold]
71 fn reserve_active_buffer_slow(&mut self, additional: usize) {
72 assert!(
73 additional <= BINVIEW_MAX_ROW_BYTE_LEN,
74 "strings longer than 2^32 - 2 are not supported"
75 );
76
77 const {
78 assert!(MAX_EXP_BLOCK_SIZE < BINVIEW_ARROW_BUFFER_LEN_LIMIT);
79 }
80
81 let new_capacity = usize::max(
83 additional,
84 (self.active_buffer.capacity() * 2).clamp(DEFAULT_BLOCK_SIZE, MAX_EXP_BLOCK_SIZE),
85 );
86
87 let old_buffer =
88 core::mem::replace(&mut self.active_buffer, Vec::with_capacity(new_capacity));
89 if !old_buffer.is_empty() {
90 self.buffer_set[self.active_buffer_idx as usize] = Buffer::from(old_buffer);
92 }
93 self.active_buffer_idx = self.buffer_set.len().try_into().unwrap();
94 self.buffer_set.push(PLACEHOLDER_BUFFER.clone()) }
96
97 pub fn push_value_ignore_validity(&mut self, bytes: &V) {
98 let bytes = bytes.to_bytes();
99 self.total_bytes_len += bytes.len();
100 unsafe {
101 let view = if bytes.len() > View::MAX_INLINE_SIZE as usize {
102 self.reserve_active_buffer(bytes.len());
103
104 let offset = self.active_buffer.len() as u32; self.active_buffer.extend_from_slice(bytes);
106 self.total_buffer_len += bytes.len();
107 View::new_noninline_unchecked(bytes, self.active_buffer_idx, offset)
108 } else {
109 View::new_inline_unchecked(bytes)
110 };
111 self.views.push(view);
112 }
113 }
114
115 pub unsafe fn push_inline_view_ignore_validity(&mut self, view: View) {
118 debug_assert!(view.is_inline());
119 self.total_bytes_len += view.length as usize;
120 self.views.push(view);
121 }
122
123 fn switch_active_stealing_bufferset_to(&mut self, buffer_set: &Buffer<Buffer<u8>>) {
124 if self
125 .last_buffer_set_stolen_from
126 .as_ref()
127 .is_some_and(|stolen_bs| {
128 stolen_bs.as_ptr() == buffer_set.as_ptr() && stolen_bs.len() >= buffer_set.len()
129 })
130 {
131 return; }
133
134 let old_gen = self.buffer_set_translation_generation;
137 self.buffer_set_translation_generation = old_gen.wrapping_add(1);
138 if self.buffer_set_translation_idxs.len() < buffer_set.len() {
139 self.buffer_set_translation_idxs
140 .resize(buffer_set.len(), (0, old_gen));
141 }
142 }
143
144 unsafe fn translate_view(
145 &mut self,
146 mut view: View,
147 other_bufferset: &Buffer<Buffer<u8>>,
148 ) -> View {
149 let (mut new_buffer_idx, gen_) = *self
151 .buffer_set_translation_idxs
152 .get_unchecked(view.buffer_idx as usize);
153 if gen_ != self.buffer_set_translation_generation {
154 let buffer = other_bufferset
158 .get_unchecked(view.buffer_idx as usize)
159 .clone()
160 .expand_end_to_storage();
161 let buf_id = buffer.as_slice().as_ptr().addr();
162 let idx = match self.stolen_buffers.entry(buf_id) {
163 Entry::Occupied(o) => *o.get(),
164 Entry::Vacant(v) => {
165 let idx = self.buffer_set.len() as u32;
166 self.total_buffer_len += buffer.len();
167 self.buffer_set.push(buffer);
168 v.insert(idx);
169 idx
170 },
171 };
172
173 *self
175 .buffer_set_translation_idxs
176 .get_unchecked_mut(view.buffer_idx as usize) =
177 (idx, self.buffer_set_translation_generation);
178 new_buffer_idx = idx;
179 }
180 view.buffer_idx = new_buffer_idx;
181 view
182 }
183
184 unsafe fn extend_views_dedup_ignore_validity(
185 &mut self,
186 views: impl IntoIterator<Item = View>,
187 other_bufferset: &Buffer<Buffer<u8>>,
188 ) {
189 self.switch_active_stealing_bufferset_to(other_bufferset);
192
193 for mut view in views {
194 if view.length > View::MAX_INLINE_SIZE {
195 view = self.translate_view(view, other_bufferset);
196 }
197 self.total_bytes_len += view.length as usize;
198 self.views.push(view);
199 }
200 }
201
202 unsafe fn extend_views_each_repeated_dedup_ignore_validity(
203 &mut self,
204 views: impl IntoIterator<Item = View>,
205 repeats: usize,
206 other_bufferset: &Buffer<Buffer<u8>>,
207 ) {
208 self.switch_active_stealing_bufferset_to(other_bufferset);
211
212 for mut view in views {
213 if view.length > View::MAX_INLINE_SIZE {
214 view = self.translate_view(view, other_bufferset);
215 }
216 self.total_bytes_len += repeats * view.length as usize;
217 for _ in 0..repeats {
218 self.views.push(view);
219 }
220 }
221 }
222}
223
224impl<V: ViewType + ?Sized> StaticArrayBuilder for BinaryViewArrayGenericBuilder<V> {
225 type Array = BinaryViewArrayGeneric<V>;
226
227 fn dtype(&self) -> &ArrowDataType {
228 &self.dtype
229 }
230
231 fn reserve(&mut self, additional: usize) {
232 self.views.reserve(additional);
233 self.validity.reserve(additional);
234 }
235
236 fn freeze(mut self) -> Self::Array {
237 if !self.active_buffer.is_empty() {
239 self.buffer_set[self.active_buffer_idx as usize] = Buffer::from(self.active_buffer);
240 } else if self.buffer_set.last().is_some_and(|b| b.is_empty()) {
241 self.buffer_set.pop();
242 }
243
244 unsafe {
245 BinaryViewArrayGeneric::new_unchecked(
246 self.dtype,
247 Buffer::from(self.views),
248 Buffer::from(self.buffer_set),
249 self.validity.into_opt_validity(),
250 Some(self.total_bytes_len),
251 self.total_buffer_len,
252 )
253 }
254 }
255
256 fn freeze_reset(&mut self) -> Self::Array {
257 if !self.active_buffer.is_empty() {
259 self.buffer_set[self.active_buffer_idx as usize] =
260 Buffer::from(core::mem::take(&mut self.active_buffer));
261 } else if self.buffer_set.last().is_some_and(|b| b.is_empty()) {
262 self.buffer_set.pop();
263 }
264
265 let out = unsafe {
266 BinaryViewArrayGeneric::new_unchecked(
267 self.dtype.clone(),
268 Buffer::from(core::mem::take(&mut self.views)),
269 Buffer::from(core::mem::take(&mut self.buffer_set)),
270 core::mem::take(&mut self.validity).into_opt_validity(),
271 Some(self.total_bytes_len),
272 self.total_buffer_len,
273 )
274 };
275
276 self.total_buffer_len = 0;
277 self.total_bytes_len = 0;
278 self.active_buffer_idx = 0;
279 self.stolen_buffers.clear();
280 self.last_buffer_set_stolen_from = None;
281 out
282 }
283
284 fn len(&self) -> usize {
285 self.views.len()
286 }
287
288 fn extend_nulls(&mut self, length: usize) {
289 self.views.extend_constant(length, View::default());
290 self.validity.extend_constant(length, false);
291 }
292
293 fn subslice_extend(
294 &mut self,
295 other: &Self::Array,
296 start: usize,
297 length: usize,
298 share: ShareStrategy,
299 ) {
300 self.views.reserve(length);
301
302 unsafe {
303 match share {
304 ShareStrategy::Never => {
305 if let Some(v) = other.validity() {
306 for i in start..start + length {
307 if v.get_bit_unchecked(i) {
308 self.push_value_ignore_validity(other.value_unchecked(i));
309 } else {
310 self.views.push(View::default())
311 }
312 }
313 } else {
314 for i in start..start + length {
315 self.push_value_ignore_validity(other.value_unchecked(i));
316 }
317 }
318 },
319 ShareStrategy::Always => {
320 let other_views = &other.views()[start..start + length];
321 self.extend_views_dedup_ignore_validity(
322 other_views.iter().copied(),
323 other.data_buffers(),
324 );
325 },
326 }
327 }
328
329 self.validity
330 .subslice_extend_from_opt_validity(other.validity(), start, length);
331 }
332
333 fn subslice_extend_each_repeated(
334 &mut self,
335 other: &Self::Array,
336 start: usize,
337 length: usize,
338 repeats: usize,
339 share: ShareStrategy,
340 ) {
341 self.views.reserve(length * repeats);
342
343 unsafe {
344 match share {
345 ShareStrategy::Never => {
346 if let Some(v) = other.validity() {
347 for i in start..start + length {
348 if v.get_bit_unchecked(i) {
349 for _ in 0..repeats {
350 self.push_value_ignore_validity(other.value_unchecked(i));
351 }
352 } else {
353 for _ in 0..repeats {
354 self.views.push(View::default())
355 }
356 }
357 }
358 } else {
359 for i in start..start + length {
360 for _ in 0..repeats {
361 self.push_value_ignore_validity(other.value_unchecked(i));
362 }
363 }
364 }
365 },
366 ShareStrategy::Always => {
367 let other_views = &other.views()[start..start + length];
368 self.extend_views_each_repeated_dedup_ignore_validity(
369 other_views.iter().copied(),
370 repeats,
371 other.data_buffers(),
372 );
373 },
374 }
375 }
376
377 self.validity
378 .subslice_extend_each_repeated_from_opt_validity(
379 other.validity(),
380 start,
381 length,
382 repeats,
383 );
384 }
385
386 unsafe fn gather_extend(
387 &mut self,
388 other: &Self::Array,
389 idxs: &[IdxSize],
390 share: ShareStrategy,
391 ) {
392 self.views.reserve(idxs.len());
393
394 unsafe {
395 match share {
396 ShareStrategy::Never => {
397 if let Some(v) = other.validity() {
398 for idx in idxs {
399 if v.get_bit_unchecked(*idx as usize) {
400 self.push_value_ignore_validity(
401 other.value_unchecked(*idx as usize),
402 );
403 } else {
404 self.views.push(View::default())
405 }
406 }
407 } else {
408 for idx in idxs {
409 self.push_value_ignore_validity(other.value_unchecked(*idx as usize));
410 }
411 }
412 },
413 ShareStrategy::Always => {
414 let other_view_slice = other.views().as_slice();
415 let other_views = idxs
416 .iter()
417 .map(|idx| *other_view_slice.get_unchecked(*idx as usize));
418 self.extend_views_dedup_ignore_validity(other_views, other.data_buffers());
419 },
420 }
421 }
422
423 self.validity
424 .gather_extend_from_opt_validity(other.validity(), idxs);
425 }
426
427 fn opt_gather_extend(&mut self, other: &Self::Array, idxs: &[IdxSize], share: ShareStrategy) {
428 self.views.reserve(idxs.len());
429
430 unsafe {
431 match share {
432 ShareStrategy::Never => {
433 if let Some(v) = other.validity() {
434 for idx in idxs {
435 if (*idx as usize) < v.len() && v.get_bit_unchecked(*idx as usize) {
436 self.push_value_ignore_validity(
437 other.value_unchecked(*idx as usize),
438 );
439 } else {
440 self.views.push(View::default())
441 }
442 }
443 } else {
444 for idx in idxs {
445 if (*idx as usize) < other.len() {
446 self.push_value_ignore_validity(
447 other.value_unchecked(*idx as usize),
448 );
449 } else {
450 self.views.push(View::default())
451 }
452 }
453 }
454 },
455 ShareStrategy::Always => {
456 let other_view_slice = other.views().as_slice();
457 let other_views = idxs.iter().map(|idx| {
458 other_view_slice
459 .get(*idx as usize)
460 .copied()
461 .unwrap_or_default()
462 });
463 self.extend_views_dedup_ignore_validity(other_views, other.data_buffers());
464 },
465 }
466 }
467
468 self.validity
469 .opt_gather_extend_from_opt_validity(other.validity(), idxs, other.len());
470 }
471}