Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions encodings/fastlanes/src/bitpacking/array/unpack_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,20 +190,14 @@ impl<'a, T: PhysicalPType, S: UnpackStrategy<T>> UnpackedChunks<'a, T, S> {
if let Some(initial) = self.initial() {
local_idx = initial.len();

// TODO(connor): use maybe_uninit_write_slice when it gets stabilized.
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
let init_initial: &[MaybeUninit<T>] = unsafe { mem::transmute(initial) };
output[..local_idx].copy_from_slice(init_initial);
output[..local_idx].write_copy_of_slice(initial);
}

local_idx = self.decode_full_chunks_into_at(output, local_idx);

if let Some(trailer) = self.trailer() {
// TODO(connor): use maybe_uninit_write_slice when it gets stabilized.
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
let init_trailer: &[MaybeUninit<T>] = unsafe { mem::transmute(trailer) };
output[local_idx..][..init_trailer.len()].copy_from_slice(init_trailer);
local_idx += init_trailer.len();
output[local_idx..][..trailer.len()].write_copy_of_slice(trailer);
local_idx += trailer.len();
}

debug_assert_eq!(local_idx, self.len);
Expand Down
6 changes: 2 additions & 4 deletions vortex-array/benches/take_slices_to_buffer_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ fn preverify(source_len: usize, starts: &[usize], lengths: &[usize], output_len:

fn copy_to_spare(result: &mut BufferMut<u16>, cursor: usize, source: &[u16]) {
let dst = &mut result.spare_capacity_mut()[cursor..][..source.len()];
// SAFETY: `dst` has exactly `source.len()` spare slots and does not overlap with source.
unsafe { copy_to_uninit(dst.as_mut_ptr().cast(), source) };
dst.write_copy_of_slice(source);
}

unsafe fn copy_to_spare_unchecked(result: &mut BufferMut<u16>, cursor: usize, source: &[u16]) {
Expand All @@ -301,8 +300,7 @@ unsafe fn copy_to_spare_unchecked(result: &mut BufferMut<u16>, cursor: usize, so
.spare_capacity_mut()
.get_unchecked_mut(cursor..cursor + source.len())
};
// SAFETY: `dst` has exactly `source.len()` spare slots and does not overlap with source.
unsafe { copy_to_uninit(dst.as_mut_ptr().cast(), source) };
dst.write_copy_of_slice(source);
}

unsafe fn copy_to_uninit(dst: *mut u16, source: &[u16]) {
Expand Down
7 changes: 2 additions & 5 deletions vortex-array/src/arrays/filter/execute/byte_compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,14 @@ fn filter_chunk_into<T: Copy>(
return;
}

let out_ptr = out.spare_capacity_mut().as_mut_ptr();
if chunk.len() == 8 && mask_byte == 0xFF {
// All 8 selected, so bulk copy.
// SAFETY: write_pos + 8 <= capacity.
unsafe {
std::ptr::copy_nonoverlapping(chunk.as_ptr(), out_ptr.add(*write_pos).cast::<T>(), 8);
}
out.spare_capacity_mut()[*write_pos..][..8].write_copy_of_slice(chunk);
*write_pos += 8;
return;
}

let out_ptr = out.spare_capacity_mut().as_mut_ptr();
let (perm, count) = &BYTE_COMPRESS_LUT[mask_byte as usize];
let count = *count as usize;
debug_assert_eq!(mask_byte & !low_bits_mask(chunk.len()), 0);
Expand Down
12 changes: 5 additions & 7 deletions vortex-array/src/arrays/filter/execute/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,14 @@ pub(super) fn filter_slice_by_bitmap<T: Copy>(slice: &[T], mask: &MaskValues) ->
let output_len = mask.true_count();
let mut out = BufferMut::<T>::with_capacity(output_len);
let src_ptr = slice.as_ptr();
let out_ptr = out.spare_capacity_mut().as_mut_ptr().cast::<T>();
let spare = out.spare_capacity_mut();
let mut write_pos = 0;

for_each_mask_word(mask, |word, word_start, word_len| {
let all_selected = low_bits_mask(word_len);
debug_assert_eq!(word & !all_selected, 0);
if word == all_selected {
// SAFETY: a full mask word selects `word_len` in-bounds source values and the output
// was allocated for every selected value.
unsafe {
ptr::copy_nonoverlapping(src_ptr.add(word_start), out_ptr.add(write_pos), word_len);
}
spare[write_pos..][..word_len].write_copy_of_slice(&slice[word_start..][..word_len]);
write_pos += word_len;
} else {
let mut selected = word;
Expand All @@ -84,7 +80,9 @@ pub(super) fn filter_slice_by_bitmap<T: Copy>(slice: &[T], mask: &MaskValues) ->
// SAFETY: set bits are limited to `word_len`, and the output was allocated for
// exactly `mask.true_count()` values.
unsafe {
out_ptr.add(write_pos).write(*src_ptr.add(index));
spare
.get_unchecked_mut(write_pos)
.write(*src_ptr.add(index));
}
write_pos += 1;
selected &= selected - 1;
Expand Down
12 changes: 1 addition & 11 deletions vortex-array/src/arrays/fixed_width/take/slices.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

use std::ptr;

use itertools::Itertools as _;
use vortex_buffer::BufferMut;
use vortex_buffer::ByteBuffer;
Expand Down Expand Up @@ -87,15 +85,7 @@ fn copy_slices(
let byte_start = start * byte_width;
let byte_length = length * byte_width;
let source = &values[byte_start..][..byte_length];
// SAFETY: `source` and the checked spare-capacity range have equal lengths and do not
// overlap.
unsafe {
ptr::copy_nonoverlapping(
source.as_ptr(),
spare[cursor..][..source.len()].as_mut_ptr().cast::<u8>(),
source.len(),
);
}
spare[cursor..][..source.len()].write_copy_of_slice(source);
Comment thread
robert3005 marked this conversation as resolved.
cursor += source.len();
}

Expand Down
19 changes: 2 additions & 17 deletions vortex-array/src/arrays/varbin/compute/take.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-FileCopyrightText: Copyright the Vortex contributors

use std::iter;
use std::ptr;
use std::sync::Arc;

use itertools::Itertools as _;
Expand Down Expand Up @@ -642,14 +641,7 @@ where
let byte_start = offset_range[0].as_();
let byte_end = offset_range[length].as_();
let src = &data[byte_start..byte_end];
// SAFETY: `src` and the checked `spare` range have equal lengths and cannot overlap.
unsafe {
ptr::copy_nonoverlapping(
src.as_ptr(),
spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
src.len(),
);
}
spare[cursor..][..src.len()].write_copy_of_slice(src);
cursor += src.len();
}
// SAFETY: the loop initialized the prefix `0..cursor` of the spare capacity.
Expand Down Expand Up @@ -735,14 +727,7 @@ where
let byte_start = offset_range[0].as_();
let byte_end = offset_range[length].as_();
let src = &data[byte_start..byte_end];
// SAFETY: `src` and the checked `spare` range have equal lengths and cannot overlap.
unsafe {
ptr::copy_nonoverlapping(
src.as_ptr(),
spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
src.len(),
);
}
spare[cursor..][..src.len()].write_copy_of_slice(src);
cursor += src.len();
}
// SAFETY: the loop initialized the prefix `0..cursor` of the spare capacity.
Expand Down
23 changes: 2 additions & 21 deletions vortex-array/src/arrays/varbinview/compute/take.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-FileCopyrightText: Copyright the Vortex contributors

use std::iter;
use std::ptr;
use std::sync::Arc;

use itertools::Itertools as _;
Expand Down Expand Up @@ -180,16 +179,7 @@ where
for &start in starts {
let start = start.as_();
let src = &source[start..][..length];
// SAFETY: `src` and the checked `spare` range have equal lengths and cannot overlap.
unsafe {
ptr::copy_nonoverlapping(
src.as_ptr(),
spare[cursor..][..src.len()]
.as_mut_ptr()
.cast::<BinaryView>(),
src.len(),
);
}
spare[cursor..][..src.len()].write_copy_of_slice(src);
cursor += src.len();
}
// SAFETY: the loop initialized the prefix `0..cursor` of the spare capacity.
Expand Down Expand Up @@ -219,16 +209,7 @@ where
let start = start.as_();
let length = length.as_();
let src = &source[start..][..length];
// SAFETY: `src` and the checked `spare` range have equal lengths and cannot overlap.
unsafe {
ptr::copy_nonoverlapping(
src.as_ptr(),
spare[cursor..][..src.len()]
.as_mut_ptr()
.cast::<BinaryView>(),
src.len(),
);
}
spare[cursor..][..src.len()].write_copy_of_slice(src);
cursor += src.len();
}
// SAFETY: the loop initialized the prefix `0..cursor` of the spare capacity.
Expand Down
5 changes: 1 addition & 4 deletions vortex-array/src/builders/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,11 @@ impl<T> UninitRange<'_, T> {
"tried to copy a slice into a `UninitRange` past its boundary"
);

// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
let uninit_src: &[MaybeUninit<T>] = unsafe { std::mem::transmute(src) };

// Note: spare_capacity_mut() returns the spare capacity starting from the current length,
// so we just use local_offset directly.
let dst =
&mut self.builder.values.spare_capacity_mut()[local_offset..local_offset + src.len()];
dst.copy_from_slice(uninit_src);
dst.write_copy_of_slice(src);
}

/// Get a mutable slice of uninitialized memory at the specified offset within this range.
Expand Down
4 changes: 2 additions & 2 deletions vortex-buffer/src/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl BufferAllocatorRef {
}

/// Copy values into a mutable buffer made by this allocator.
pub fn copy_from<T>(&self, values: impl AsRef<[T]>) -> BufferMut<T> {
pub fn copy_from<T: Copy>(&self, values: impl AsRef<[T]>) -> BufferMut<T> {
BufferMut::copy_from_in(values, self.clone())
}
}
Expand Down Expand Up @@ -182,7 +182,7 @@ impl StaticBufferAllocator {
}

/// Copy values into a mutable buffer made by the static allocator.
pub fn copy_from<T>(values: impl AsRef<[T]>) -> BufferMut<T> {
pub fn copy_from<T: Copy>(values: impl AsRef<[T]>) -> BufferMut<T> {
BufferMut::copy_from(values)
}
}
Expand Down
30 changes: 24 additions & 6 deletions vortex-buffer/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,18 @@ impl<T> Buffer<T> {
/// of the provided `Vec<T>` while maintaining the ability to convert it back into a mutable
/// buffer. We could fix this by forking `Bytes`, or in many other complex ways, but for now
/// callers should prefer to construct `Buffer<T>` from a `BufferMut<T>`.
pub fn copy_from(values: impl AsRef<[T]>) -> Self {
pub fn copy_from(values: impl AsRef<[T]>) -> Self
where
T: Copy,
{
BufferMut::copy_from(values).freeze()
}

/// Returns a new `Buffer<T>` copied with the provided allocator.
pub fn copy_from_in(values: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self {
pub fn copy_from_in(values: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self
where
T: Copy,
{
BufferMut::copy_from_in(values, allocator).freeze()
}

Expand All @@ -182,7 +188,10 @@ impl<T> Buffer<T> {
/// `alignment`. Use [`copy_from_preferred_aligned`] to control the over-alignment.
///
/// [`copy_from_preferred_aligned`]: Self::copy_from_preferred_aligned
pub fn copy_from_aligned(values: impl AsRef<[T]>, alignment: Alignment) -> Self {
pub fn copy_from_aligned(values: impl AsRef<[T]>, alignment: Alignment) -> Self
where
T: Copy,
{
Self::copy_from_preferred_aligned(values, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
}

Expand All @@ -194,7 +203,10 @@ impl<T> Buffer<T> {
values: impl AsRef<[T]>,
alignment: Alignment,
preferred_alignment: Option<Alignment>,
) -> Self {
) -> Self
where
T: Copy,
{
BufferMut::copy_from_preferred_aligned(values, alignment, preferred_alignment).freeze()
}

Expand Down Expand Up @@ -670,7 +682,10 @@ impl<T> Buffer<T> {
}

/// Convert self into `BufferMut<T>`, cloning the data if there are multiple strong references.
pub fn into_mut(self) -> BufferMut<T> {
pub fn into_mut(self) -> BufferMut<T>
where
T: Copy,
{
self.try_into_mut().unwrap_or_else(|buffer| {
let allocator = buffer.allocator().clone();
BufferMut::<T>::copy_from_aligned_in(&buffer, buffer.alignment, allocator)
Expand All @@ -683,7 +698,10 @@ impl<T> Buffer<T> {
}

/// Return a `Buffer<T>` with the given alignment. Where possible, this will be zero-copy.
pub fn aligned(mut self, alignment: Alignment) -> Self {
pub fn aligned(mut self, alignment: Alignment) -> Self
where
T: Copy,
{
if alignment.is_ptr_aligned(self.as_ptr()) {
self.alignment = alignment;
self
Expand Down
Loading
Loading