Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-arrow/src/array/binview/mod.rs
6939 views
1
#![allow(unsafe_op_in_unsafe_fn)]
2
//! See thread: https://lists.apache.org/thread/w88tpz76ox8h3rxkjl4so6rg3f1rv7wt
3
4
mod builder;
5
pub use builder::*;
6
mod ffi;
7
pub(super) mod fmt;
8
mod iterator;
9
mod mutable;
10
#[cfg(feature = "proptest")]
11
pub mod proptest;
12
mod view;
13
14
use std::any::Any;
15
use std::fmt::Debug;
16
use std::marker::PhantomData;
17
use std::sync::Arc;
18
19
use polars_error::*;
20
use polars_utils::relaxed_cell::RelaxedCell;
21
22
use crate::array::Array;
23
use crate::bitmap::Bitmap;
24
use crate::buffer::Buffer;
25
use crate::datatypes::ArrowDataType;
26
27
mod private {
28
pub trait Sealed: Send + Sync {}
29
30
impl Sealed for str {}
31
impl Sealed for [u8] {}
32
}
33
pub use iterator::BinaryViewValueIter;
34
pub use mutable::MutableBinaryViewArray;
35
use polars_utils::aliases::{InitHashMaps, PlHashMap};
36
use private::Sealed;
37
38
use crate::array::binview::view::{validate_binary_views, validate_views_utf8_only};
39
use crate::array::iterator::NonNullValuesIter;
40
use crate::bitmap::utils::{BitmapIter, ZipValidity};
41
pub type BinaryViewArray = BinaryViewArrayGeneric<[u8]>;
42
pub type Utf8ViewArray = BinaryViewArrayGeneric<str>;
43
pub type BinaryViewArrayBuilder = BinaryViewArrayGenericBuilder<[u8]>;
44
pub type Utf8ViewArrayBuilder = BinaryViewArrayGenericBuilder<str>;
45
pub use view::{View, validate_utf8_views};
46
47
use super::Splitable;
48
49
pub type MutablePlString = MutableBinaryViewArray<str>;
50
pub type MutablePlBinary = MutableBinaryViewArray<[u8]>;
51
52
static BIN_VIEW_TYPE: ArrowDataType = ArrowDataType::BinaryView;
53
static UTF8_VIEW_TYPE: ArrowDataType = ArrowDataType::Utf8View;
54
55
// Growth parameters of view array buffers.
56
const DEFAULT_BLOCK_SIZE: usize = 8 * 1024;
57
const MAX_EXP_BLOCK_SIZE: usize = 16 * 1024 * 1024;
58
59
pub trait ViewType: Sealed + 'static + PartialEq + AsRef<Self> {
60
const IS_UTF8: bool;
61
const DATA_TYPE: ArrowDataType;
62
type Owned: Debug + Clone + Sync + Send + AsRef<Self>;
63
64
/// # Safety
65
/// The caller must ensure that `slice` is a valid view.
66
unsafe fn from_bytes_unchecked(slice: &[u8]) -> &Self;
67
fn from_bytes(slice: &[u8]) -> Option<&Self>;
68
69
fn to_bytes(&self) -> &[u8];
70
71
#[allow(clippy::wrong_self_convention)]
72
fn into_owned(&self) -> Self::Owned;
73
74
fn dtype() -> &'static ArrowDataType;
75
}
76
77
impl ViewType for str {
78
const IS_UTF8: bool = true;
79
const DATA_TYPE: ArrowDataType = ArrowDataType::Utf8View;
80
type Owned = String;
81
82
#[inline(always)]
83
unsafe fn from_bytes_unchecked(slice: &[u8]) -> &Self {
84
std::str::from_utf8_unchecked(slice)
85
}
86
#[inline(always)]
87
fn from_bytes(slice: &[u8]) -> Option<&Self> {
88
std::str::from_utf8(slice).ok()
89
}
90
91
#[inline(always)]
92
fn to_bytes(&self) -> &[u8] {
93
self.as_bytes()
94
}
95
96
fn into_owned(&self) -> Self::Owned {
97
self.to_string()
98
}
99
fn dtype() -> &'static ArrowDataType {
100
&UTF8_VIEW_TYPE
101
}
102
}
103
104
impl ViewType for [u8] {
105
const IS_UTF8: bool = false;
106
const DATA_TYPE: ArrowDataType = ArrowDataType::BinaryView;
107
type Owned = Vec<u8>;
108
109
#[inline(always)]
110
unsafe fn from_bytes_unchecked(slice: &[u8]) -> &Self {
111
slice
112
}
113
#[inline(always)]
114
fn from_bytes(slice: &[u8]) -> Option<&Self> {
115
Some(slice)
116
}
117
118
#[inline(always)]
119
fn to_bytes(&self) -> &[u8] {
120
self
121
}
122
123
fn into_owned(&self) -> Self::Owned {
124
self.to_vec()
125
}
126
127
fn dtype() -> &'static ArrowDataType {
128
&BIN_VIEW_TYPE
129
}
130
}
131
132
pub struct BinaryViewArrayGeneric<T: ViewType + ?Sized> {
133
dtype: ArrowDataType,
134
views: Buffer<View>,
135
buffers: Arc<[Buffer<u8>]>,
136
validity: Option<Bitmap>,
137
phantom: PhantomData<T>,
138
/// Total bytes length if we would concatenate them all.
139
total_bytes_len: RelaxedCell<u64>,
140
/// Total bytes in the buffer (excluding remaining capacity)
141
total_buffer_len: usize,
142
}
143
144
impl<T: ViewType + ?Sized> PartialEq for BinaryViewArrayGeneric<T> {
145
fn eq(&self, other: &Self) -> bool {
146
self.len() == other.len() && self.into_iter().zip(other).all(|(l, r)| l == r)
147
}
148
}
149
150
impl<T: ViewType + ?Sized> Clone for BinaryViewArrayGeneric<T> {
151
fn clone(&self) -> Self {
152
Self {
153
dtype: self.dtype.clone(),
154
views: self.views.clone(),
155
buffers: self.buffers.clone(),
156
validity: self.validity.clone(),
157
phantom: Default::default(),
158
total_bytes_len: self.total_bytes_len.clone(),
159
total_buffer_len: self.total_buffer_len,
160
}
161
}
162
}
163
164
unsafe impl<T: ViewType + ?Sized> Send for BinaryViewArrayGeneric<T> {}
165
unsafe impl<T: ViewType + ?Sized> Sync for BinaryViewArrayGeneric<T> {}
166
167
const UNKNOWN_LEN: u64 = u64::MAX;
168
169
impl<T: ViewType + ?Sized> BinaryViewArrayGeneric<T> {
170
/// # Safety
171
/// The caller must ensure
172
/// - the data is valid utf8 (if required)
173
/// - The offsets match the buffers.
174
pub unsafe fn new_unchecked(
175
dtype: ArrowDataType,
176
views: Buffer<View>,
177
buffers: Arc<[Buffer<u8>]>,
178
validity: Option<Bitmap>,
179
total_bytes_len: usize,
180
total_buffer_len: usize,
181
) -> Self {
182
// Verify the invariants
183
#[cfg(debug_assertions)]
184
{
185
if let Some(validity) = validity.as_ref() {
186
assert_eq!(validity.len(), views.len());
187
}
188
189
// @TODO: Enable this. This is currently bugged with concatenate.
190
// let mut actual_total_buffer_len = 0;
191
// let mut actual_total_bytes_len = 0;
192
//
193
// for buffer in buffers.iter() {
194
// actual_total_buffer_len += buffer.len();
195
// }
196
197
for (i, view) in views.iter().enumerate() {
198
let is_valid = validity.as_ref().is_none_or(|v| v.get_bit(i));
199
200
if !is_valid {
201
continue;
202
}
203
204
// actual_total_bytes_len += view.length as usize;
205
if view.length > View::MAX_INLINE_SIZE {
206
assert!((view.buffer_idx as usize) < (buffers.len()));
207
assert!(
208
view.offset as usize + view.length as usize
209
<= buffers[view.buffer_idx as usize].len()
210
);
211
}
212
}
213
214
// assert_eq!(actual_total_buffer_len, total_buffer_len);
215
// if (total_bytes_len as u64) != UNKNOWN_LEN {
216
// assert_eq!(actual_total_bytes_len, total_bytes_len);
217
// }
218
}
219
220
Self {
221
dtype,
222
views,
223
buffers,
224
validity,
225
phantom: Default::default(),
226
total_bytes_len: RelaxedCell::from(total_bytes_len as u64),
227
total_buffer_len,
228
}
229
}
230
231
/// Create a new BinaryViewArray but initialize a statistics compute.
232
///
233
/// # Safety
234
/// The caller must ensure the invariants
235
pub unsafe fn new_unchecked_unknown_md(
236
dtype: ArrowDataType,
237
views: Buffer<View>,
238
buffers: Arc<[Buffer<u8>]>,
239
validity: Option<Bitmap>,
240
total_buffer_len: Option<usize>,
241
) -> Self {
242
let total_bytes_len = UNKNOWN_LEN as usize;
243
let total_buffer_len =
244
total_buffer_len.unwrap_or_else(|| buffers.iter().map(|b| b.len()).sum());
245
Self::new_unchecked(
246
dtype,
247
views,
248
buffers,
249
validity,
250
total_bytes_len,
251
total_buffer_len,
252
)
253
}
254
255
pub fn data_buffers(&self) -> &Arc<[Buffer<u8>]> {
256
&self.buffers
257
}
258
259
pub fn variadic_buffer_lengths(&self) -> Vec<i64> {
260
self.buffers.iter().map(|buf| buf.len() as i64).collect()
261
}
262
263
pub fn views(&self) -> &Buffer<View> {
264
&self.views
265
}
266
267
pub fn into_views(self) -> Vec<View> {
268
self.views.make_mut()
269
}
270
271
pub fn into_inner(
272
self,
273
) -> (
274
Buffer<View>,
275
Arc<[Buffer<u8>]>,
276
Option<Bitmap>,
277
usize,
278
usize,
279
) {
280
let views = self.views;
281
let buffers = self.buffers;
282
let validity = self.validity;
283
284
(
285
views,
286
buffers,
287
validity,
288
self.total_bytes_len.load() as usize,
289
self.total_buffer_len,
290
)
291
}
292
293
/// Apply a function over the views. This can be used to update views in operations like slicing.
294
///
295
/// # Safety
296
/// Update the views. All invariants of the views apply.
297
pub unsafe fn apply_views<F: FnMut(View, &T) -> View>(&self, mut update_view: F) -> Self {
298
let arr = self.clone();
299
let (views, buffers, validity, total_bytes_len, total_buffer_len) = arr.into_inner();
300
301
let mut views = views.make_mut();
302
for v in views.iter_mut() {
303
let str_slice = T::from_bytes_unchecked(v.get_slice_unchecked(&buffers));
304
*v = update_view(*v, str_slice);
305
}
306
Self::new_unchecked(
307
self.dtype.clone(),
308
views.into(),
309
buffers,
310
validity,
311
total_bytes_len,
312
total_buffer_len,
313
)
314
}
315
316
pub fn try_new(
317
dtype: ArrowDataType,
318
views: Buffer<View>,
319
buffers: Arc<[Buffer<u8>]>,
320
validity: Option<Bitmap>,
321
) -> PolarsResult<Self> {
322
if T::IS_UTF8 {
323
validate_utf8_views(views.as_ref(), buffers.as_ref())?;
324
} else {
325
validate_binary_views(views.as_ref(), buffers.as_ref())?;
326
}
327
328
if let Some(validity) = &validity {
329
polars_ensure!(validity.len()== views.len(), ComputeError: "validity mask length must match the number of values" )
330
}
331
332
unsafe {
333
Ok(Self::new_unchecked_unknown_md(
334
dtype, views, buffers, validity, None,
335
))
336
}
337
}
338
339
/// Creates an empty [`BinaryViewArrayGeneric`], i.e. whose `.len` is zero.
340
#[inline]
341
pub fn new_empty(dtype: ArrowDataType) -> Self {
342
unsafe { Self::new_unchecked(dtype, Buffer::new(), Arc::from([]), None, 0, 0) }
343
}
344
345
/// Returns a new null [`BinaryViewArrayGeneric`] of `length`.
346
#[inline]
347
pub fn new_null(dtype: ArrowDataType, length: usize) -> Self {
348
let validity = Some(Bitmap::new_zeroed(length));
349
unsafe { Self::new_unchecked(dtype, Buffer::zeroed(length), Arc::from([]), validity, 0, 0) }
350
}
351
352
/// Returns the element at index `i`
353
/// # Panics
354
/// iff `i >= self.len()`
355
#[inline]
356
pub fn value(&self, i: usize) -> &T {
357
assert!(i < self.len());
358
unsafe { self.value_unchecked(i) }
359
}
360
361
/// Returns the element at index `i`
362
///
363
/// # Safety
364
/// Assumes that the `i < self.len`.
365
#[inline]
366
pub unsafe fn value_unchecked(&self, i: usize) -> &T {
367
let v = self.views.get_unchecked(i);
368
T::from_bytes_unchecked(v.get_slice_unchecked(&self.buffers))
369
}
370
371
/// Returns the element at index `i`, or None if it is null.
372
/// # Panics
373
/// iff `i >= self.len()`
374
#[inline]
375
pub fn get(&self, i: usize) -> Option<&T> {
376
assert!(i < self.len());
377
unsafe { self.get_unchecked(i) }
378
}
379
380
/// Returns the element at index `i`, or None if it is null.
381
///
382
/// # Safety
383
/// Assumes that the `i < self.len`.
384
#[inline]
385
pub unsafe fn get_unchecked(&self, i: usize) -> Option<&T> {
386
if self
387
.validity
388
.as_ref()
389
.is_none_or(|v| v.get_bit_unchecked(i))
390
{
391
let v = self.views.get_unchecked(i);
392
Some(T::from_bytes_unchecked(
393
v.get_slice_unchecked(&self.buffers),
394
))
395
} else {
396
None
397
}
398
}
399
400
/// Returns an iterator of `Option<&T>` over every element of this array.
401
pub fn iter(&self) -> ZipValidity<&T, BinaryViewValueIter<'_, T>, BitmapIter<'_>> {
402
ZipValidity::new_with_validity(self.values_iter(), self.validity.as_ref())
403
}
404
405
/// Returns an iterator of `&[u8]` over every element of this array, ignoring the validity
406
pub fn values_iter(&self) -> BinaryViewValueIter<'_, T> {
407
BinaryViewValueIter::new(self)
408
}
409
410
pub fn len_iter(&self) -> impl Iterator<Item = u32> + '_ {
411
self.views.iter().map(|v| v.length)
412
}
413
414
/// Returns an iterator of the non-null values.
415
pub fn non_null_values_iter(&self) -> NonNullValuesIter<'_, BinaryViewArrayGeneric<T>> {
416
NonNullValuesIter::new(self, self.validity())
417
}
418
419
/// Returns an iterator of the non-null values.
420
pub fn non_null_views_iter(&self) -> NonNullValuesIter<'_, Buffer<View>> {
421
NonNullValuesIter::new(self.views(), self.validity())
422
}
423
424
impl_sliced!();
425
impl_mut_validity!();
426
impl_into_array!();
427
428
pub fn from_slice<S: AsRef<T>, P: AsRef<[Option<S>]>>(slice: P) -> Self {
429
let mutable = MutableBinaryViewArray::from_iterator(
430
slice.as_ref().iter().map(|opt_v| opt_v.as_ref()),
431
);
432
mutable.into()
433
}
434
435
pub fn from_slice_values<S: AsRef<T>, P: AsRef<[S]>>(slice: P) -> Self {
436
let mutable =
437
MutableBinaryViewArray::from_values_iter(slice.as_ref().iter().map(|v| v.as_ref()));
438
mutable.into()
439
}
440
441
/// Get the total length of bytes that it would take to concatenate all binary/str values in this array.
442
pub fn total_bytes_len(&self) -> usize {
443
let total = self.total_bytes_len.load();
444
if total == UNKNOWN_LEN {
445
let total = self.len_iter().map(|v| v as usize).sum::<usize>();
446
self.total_bytes_len.store(total as u64);
447
total
448
} else {
449
total as usize
450
}
451
}
452
453
/// Get the length of bytes that are stored in the variadic buffers.
454
pub fn total_buffer_len(&self) -> usize {
455
self.total_buffer_len
456
}
457
458
fn total_unshared_buffer_len(&self) -> usize {
459
// XXX: it is O(n), not O(1).
460
// Given this function is only called in `maybe_gc()`,
461
// it may not be worthy to add an extra field for this.
462
self.buffers
463
.iter()
464
.map(|buf| {
465
if buf.storage_refcount() > 1 {
466
0
467
} else {
468
buf.len()
469
}
470
})
471
.sum()
472
}
473
474
#[inline(always)]
475
pub fn len(&self) -> usize {
476
self.views.len()
477
}
478
479
/// Garbage collect
480
pub fn gc(self) -> Self {
481
if self.buffers.is_empty() {
482
return self;
483
}
484
let mut mutable = MutableBinaryViewArray::with_capacity(self.len());
485
let buffers = self.buffers.as_ref();
486
487
for view in self.views.as_ref() {
488
unsafe { mutable.push_view_unchecked(*view, buffers) }
489
}
490
mutable.freeze().with_validity(self.validity)
491
}
492
493
pub fn deshare(&self) -> Self {
494
if Arc::strong_count(&self.buffers) == 1
495
&& self.buffers.iter().all(|b| b.storage_refcount() == 1)
496
{
497
return self.clone();
498
}
499
self.clone().gc()
500
}
501
502
pub fn is_sliced(&self) -> bool {
503
!std::ptr::eq(self.views.as_ptr(), self.views.storage_ptr())
504
}
505
506
pub fn maybe_gc(self) -> Self {
507
const GC_MINIMUM_SAVINGS: usize = 16 * 1024; // At least 16 KiB.
508
509
if self.total_buffer_len <= GC_MINIMUM_SAVINGS {
510
return self;
511
}
512
513
if Arc::strong_count(&self.buffers) != 1 {
514
// There are multiple holders of this `buffers`.
515
// If we allow gc in this case,
516
// it may end up copying the same content multiple times.
517
return self;
518
}
519
520
// Subtract the maximum amount of inlined strings to get a lower bound
521
// on the number of buffer bytes needed (assuming no dedup).
522
let total_bytes_len = self.total_bytes_len();
523
let buffer_req_lower_bound = total_bytes_len.saturating_sub(self.len() * 12);
524
525
let lower_bound_mem_usage_post_gc = self.len() * 16 + buffer_req_lower_bound;
526
// Use unshared buffer len. Shared buffer won't be freed; no savings.
527
let cur_mem_usage = self.len() * 16 + self.total_unshared_buffer_len();
528
let savings_upper_bound = cur_mem_usage.saturating_sub(lower_bound_mem_usage_post_gc);
529
530
if savings_upper_bound >= GC_MINIMUM_SAVINGS
531
&& cur_mem_usage >= 4 * lower_bound_mem_usage_post_gc
532
{
533
self.gc()
534
} else {
535
self
536
}
537
}
538
539
pub fn make_mut(self) -> MutableBinaryViewArray<T> {
540
let views = self.views.make_mut();
541
let completed_buffers = self.buffers.to_vec();
542
let validity = self.validity.map(|bitmap| bitmap.make_mut());
543
544
// We need to know the total_bytes_len if we are going to mutate it.
545
let mut total_bytes_len = self.total_bytes_len.load();
546
if total_bytes_len == UNKNOWN_LEN {
547
total_bytes_len = views.iter().map(|view| view.length as u64).sum();
548
}
549
let total_bytes_len = total_bytes_len as usize;
550
551
MutableBinaryViewArray {
552
views,
553
completed_buffers,
554
in_progress_buffer: vec![],
555
validity,
556
phantom: Default::default(),
557
total_bytes_len,
558
total_buffer_len: self.total_buffer_len,
559
stolen_buffers: PlHashMap::new(),
560
}
561
}
562
}
563
564
impl BinaryViewArray {
565
/// Validate the underlying bytes on UTF-8.
566
pub fn validate_utf8(&self) -> PolarsResult<()> {
567
// SAFETY: views are correct
568
unsafe { validate_views_utf8_only(&self.views, &self.buffers, 0) }
569
}
570
571
/// Convert [`BinaryViewArray`] to [`Utf8ViewArray`].
572
pub fn to_utf8view(&self) -> PolarsResult<Utf8ViewArray> {
573
self.validate_utf8()?;
574
unsafe { Ok(self.to_utf8view_unchecked()) }
575
}
576
577
/// Convert [`BinaryViewArray`] to [`Utf8ViewArray`] without checking UTF-8.
578
///
579
/// # Safety
580
/// The caller must ensure the underlying data is valid UTF-8.
581
pub unsafe fn to_utf8view_unchecked(&self) -> Utf8ViewArray {
582
Utf8ViewArray::new_unchecked(
583
ArrowDataType::Utf8View,
584
self.views.clone(),
585
self.buffers.clone(),
586
self.validity.clone(),
587
self.total_bytes_len.load() as usize,
588
self.total_buffer_len,
589
)
590
}
591
}
592
593
impl Utf8ViewArray {
594
pub fn to_binview(&self) -> BinaryViewArray {
595
// SAFETY: same invariants.
596
unsafe {
597
BinaryViewArray::new_unchecked(
598
ArrowDataType::BinaryView,
599
self.views.clone(),
600
self.buffers.clone(),
601
self.validity.clone(),
602
self.total_bytes_len.load() as usize,
603
self.total_buffer_len,
604
)
605
}
606
}
607
}
608
609
impl<T: ViewType + ?Sized> Array for BinaryViewArrayGeneric<T> {
610
fn as_any(&self) -> &dyn Any {
611
self
612
}
613
614
fn as_any_mut(&mut self) -> &mut dyn Any {
615
self
616
}
617
618
#[inline(always)]
619
fn len(&self) -> usize {
620
BinaryViewArrayGeneric::len(self)
621
}
622
623
fn dtype(&self) -> &ArrowDataType {
624
T::dtype()
625
}
626
627
fn validity(&self) -> Option<&Bitmap> {
628
self.validity.as_ref()
629
}
630
631
fn split_at_boxed(&self, offset: usize) -> (Box<dyn Array>, Box<dyn Array>) {
632
let (lhs, rhs) = Splitable::split_at(self, offset);
633
(Box::new(lhs), Box::new(rhs))
634
}
635
636
unsafe fn split_at_boxed_unchecked(&self, offset: usize) -> (Box<dyn Array>, Box<dyn Array>) {
637
let (lhs, rhs) = unsafe { Splitable::split_at_unchecked(self, offset) };
638
(Box::new(lhs), Box::new(rhs))
639
}
640
641
fn slice(&mut self, offset: usize, length: usize) {
642
assert!(
643
offset + length <= self.len(),
644
"the offset of the new Buffer cannot exceed the existing length"
645
);
646
unsafe { self.slice_unchecked(offset, length) }
647
}
648
649
unsafe fn slice_unchecked(&mut self, offset: usize, length: usize) {
650
debug_assert!(offset + length <= self.len());
651
self.validity = self
652
.validity
653
.take()
654
.map(|bitmap| bitmap.sliced_unchecked(offset, length))
655
.filter(|bitmap| bitmap.unset_bits() > 0);
656
self.views.slice_unchecked(offset, length);
657
self.total_bytes_len.store(UNKNOWN_LEN)
658
}
659
660
fn with_validity(&self, validity: Option<Bitmap>) -> Box<dyn Array> {
661
debug_assert!(
662
validity.as_ref().is_none_or(|v| v.len() == self.len()),
663
"{} != {}",
664
validity.as_ref().unwrap().len(),
665
self.len()
666
);
667
668
let mut new = self.clone();
669
new.validity = validity;
670
Box::new(new)
671
}
672
673
fn to_boxed(&self) -> Box<dyn Array> {
674
Box::new(self.clone())
675
}
676
}
677
678
impl<T: ViewType + ?Sized> Splitable for BinaryViewArrayGeneric<T> {
679
fn check_bound(&self, offset: usize) -> bool {
680
offset <= self.len()
681
}
682
683
unsafe fn _split_at_unchecked(&self, offset: usize) -> (Self, Self) {
684
let (lhs_views, rhs_views) = unsafe { self.views.split_at_unchecked(offset) };
685
let (lhs_validity, rhs_validity) = unsafe { self.validity.split_at_unchecked(offset) };
686
687
unsafe {
688
(
689
Self::new_unchecked(
690
self.dtype.clone(),
691
lhs_views,
692
self.buffers.clone(),
693
lhs_validity,
694
if offset == 0 { 0 } else { UNKNOWN_LEN as _ },
695
self.total_buffer_len(),
696
),
697
Self::new_unchecked(
698
self.dtype.clone(),
699
rhs_views,
700
self.buffers.clone(),
701
rhs_validity,
702
if offset == self.len() {
703
0
704
} else {
705
UNKNOWN_LEN as _
706
},
707
self.total_buffer_len(),
708
),
709
)
710
}
711
}
712
}
713
714