Skip to content

Commit bc8ba3c

Browse files
authored
Add Zero-Copy Conversion between Vec and MutableBuffer (#3920)
* Add Zero-Copy Conversion between Vec and MutableBuffer * Update test * Fix docs * Clippy
1 parent 1500c9b commit bc8ba3c

File tree

5 files changed

+102
-197
lines changed

5 files changed

+102
-197
lines changed

arrow-array/src/array/list_array.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -842,10 +842,8 @@ mod tests {
842842

843843
#[test]
844844
#[should_panic(expected = "memory is not aligned")]
845-
#[allow(deprecated)]
846845
fn test_primitive_array_alignment() {
847-
let ptr = arrow_buffer::alloc::allocate_aligned(8);
848-
let buf = unsafe { Buffer::from_raw_parts(ptr, 8, 8) };
846+
let buf = Buffer::from_slice_ref([0_u64]);
849847
let buf2 = buf.slice(1);
850848
let array_data = ArrayData::builder(DataType::Int32)
851849
.add_buffer(buf2)
@@ -859,10 +857,8 @@ mod tests {
859857
// Different error messages, so skip for now
860858
// https://github.com/apache/arrow-rs/issues/1545
861859
#[cfg(not(feature = "force_validate"))]
862-
#[allow(deprecated)]
863860
fn test_list_array_alignment() {
864-
let ptr = arrow_buffer::alloc::allocate_aligned(8);
865-
let buf = unsafe { Buffer::from_raw_parts(ptr, 8, 8) };
861+
let buf = Buffer::from_slice_ref([0_u64]);
866862
let buf2 = buf.slice(1);
867863

868864
let values: [i32; 8] = [0; 8];

arrow-buffer/src/alloc/mod.rs

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -18,117 +18,15 @@
1818
//! Defines memory-related functions, such as allocate/deallocate/reallocate memory
1919
//! regions, cache and allocation alignments.
2020
21-
use std::alloc::{handle_alloc_error, Layout};
21+
use std::alloc::Layout;
2222
use std::fmt::{Debug, Formatter};
2323
use std::panic::RefUnwindSafe;
24-
use std::ptr::NonNull;
2524
use std::sync::Arc;
2625

2726
mod alignment;
2827

2928
pub use alignment::ALIGNMENT;
3029

31-
/// Returns an aligned non null pointer similar to [`NonNull::dangling`]
32-
///
33-
/// Note that the pointer value may potentially represent a valid pointer, which means
34-
/// this must not be used as a "not yet initialized" sentinel value.
35-
///
36-
/// Types that lazily allocate must track initialization by some other means.
37-
#[inline]
38-
fn dangling_ptr() -> NonNull<u8> {
39-
// SAFETY: ALIGNMENT is a non-zero usize which is then casted
40-
// to a *mut T. Therefore, `ptr` is not null and the conditions for
41-
// calling new_unchecked() are respected.
42-
unsafe { NonNull::new_unchecked(ALIGNMENT as *mut u8) }
43-
}
44-
45-
/// Allocates a cache-aligned memory region of `size` bytes with uninitialized values.
46-
/// This is more performant than using [allocate_aligned_zeroed] when all bytes will have
47-
/// an unknown or non-zero value and is semantically similar to `malloc`.
48-
#[deprecated(note = "Use Vec")]
49-
pub fn allocate_aligned(size: usize) -> NonNull<u8> {
50-
unsafe {
51-
if size == 0 {
52-
dangling_ptr()
53-
} else {
54-
let layout = Layout::from_size_align_unchecked(size, ALIGNMENT);
55-
let raw_ptr = std::alloc::alloc(layout);
56-
NonNull::new(raw_ptr).unwrap_or_else(|| handle_alloc_error(layout))
57-
}
58-
}
59-
}
60-
61-
/// Allocates a cache-aligned memory region of `size` bytes with `0` on all of them.
62-
/// This is more performant than using [allocate_aligned] and setting all bytes to zero
63-
/// and is semantically similar to `calloc`.
64-
#[deprecated(note = "Use Vec")]
65-
pub fn allocate_aligned_zeroed(size: usize) -> NonNull<u8> {
66-
unsafe {
67-
if size == 0 {
68-
dangling_ptr()
69-
} else {
70-
let layout = Layout::from_size_align_unchecked(size, ALIGNMENT);
71-
let raw_ptr = std::alloc::alloc_zeroed(layout);
72-
NonNull::new(raw_ptr).unwrap_or_else(|| handle_alloc_error(layout))
73-
}
74-
}
75-
}
76-
77-
/// # Safety
78-
///
79-
/// This function is unsafe because undefined behavior can result if the caller does not ensure all
80-
/// of the following:
81-
///
82-
/// * ptr must denote a block of memory currently allocated via this allocator,
83-
///
84-
/// * size must be the same size that was used to allocate that block of memory,
85-
#[deprecated(note = "Use Vec")]
86-
pub unsafe fn free_aligned(ptr: NonNull<u8>, size: usize) {
87-
if size != 0 {
88-
std::alloc::dealloc(
89-
ptr.as_ptr() as *mut u8,
90-
Layout::from_size_align_unchecked(size, ALIGNMENT),
91-
);
92-
}
93-
}
94-
95-
/// # Safety
96-
///
97-
/// This function is unsafe because undefined behavior can result if the caller does not ensure all
98-
/// of the following:
99-
///
100-
/// * ptr must be currently allocated via this allocator,
101-
///
102-
/// * new_size must be greater than zero.
103-
///
104-
/// * new_size, when rounded up to the nearest multiple of [ALIGNMENT], must not overflow (i.e.,
105-
/// the rounded value must be less than usize::MAX).
106-
#[deprecated(note = "Use Vec")]
107-
#[allow(deprecated)]
108-
pub unsafe fn reallocate(
109-
ptr: NonNull<u8>,
110-
old_size: usize,
111-
new_size: usize,
112-
) -> NonNull<u8> {
113-
if old_size == 0 {
114-
return allocate_aligned(new_size);
115-
}
116-
117-
if new_size == 0 {
118-
free_aligned(ptr, old_size);
119-
return dangling_ptr();
120-
}
121-
122-
let raw_ptr = std::alloc::realloc(
123-
ptr.as_ptr() as *mut u8,
124-
Layout::from_size_align_unchecked(old_size, ALIGNMENT),
125-
new_size,
126-
);
127-
NonNull::new(raw_ptr).unwrap_or_else(|| {
128-
handle_alloc_error(Layout::from_size_align_unchecked(new_size, ALIGNMENT))
129-
})
130-
}
131-
13230
/// The owner of an allocation.
13331
/// The trait implementation is responsible for dropping the allocations once no more references exist.
13432
pub trait Allocation: RefUnwindSafe + Send + Sync {}

arrow-buffer/src/buffer/immutable.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,10 @@ impl Buffer {
7171
}
7272
}
7373

74-
/// Create a [`Buffer`] from the provided `Vec` without copying
74+
/// Create a [`Buffer`] from the provided [`Vec`] without copying
7575
#[inline]
7676
pub fn from_vec<T: ArrowNativeType>(vec: Vec<T>) -> Self {
77-
// Safety
78-
// Vec::as_ptr guaranteed to not be null and ArrowNativeType are trivially transmutable
79-
let ptr = unsafe { NonNull::new_unchecked(vec.as_ptr() as _) };
80-
let len = vec.len() * std::mem::size_of::<T>();
81-
// Safety
82-
// Vec guaranteed to have a valid layout matching that of `Layout::array`
83-
// This is based on `RawVec::current_memory`
84-
let layout = unsafe { Layout::array::<T>(vec.capacity()).unwrap_unchecked() };
85-
std::mem::forget(vec);
86-
let b = unsafe { Bytes::new(ptr, len, Deallocation::Standard(layout)) };
87-
Self::from_bytes(b)
77+
MutableBuffer::from_vec(vec).into()
8878
}
8979

9080
/// Initializes a [Buffer] from a slice of items.
@@ -810,7 +800,8 @@ mod tests {
810800
b.into_mutable().unwrap();
811801

812802
let b = Buffer::from_vec(vec![1_u32, 3, 5]);
813-
let b = b.into_mutable().unwrap_err(); // Invalid layout
803+
let b = b.into_mutable().unwrap();
804+
let b = Buffer::from(b);
814805
let b = b.into_vec::<u32>().unwrap();
815806
assert_eq!(b, &[1, 3, 5]);
816807
}

0 commit comments

Comments
 (0)