Skip to content

Commit fd2feb7

Browse files
committed
Merge remote-tracking branch 'origin/develop' into ji/chunked-array-store-child-offset-mem
# Conflicts: # vortex-array/src/arrays/chunked/vtable/mod.rs
2 parents 7fc89bf + bec5098 commit fd2feb7

File tree

74 files changed

+2928
-717
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2928
-717
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

encodings/alp/src/alp/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ pub trait ALPFloat: private::Sealed + Float + Display + NativePType {
225225
encoded.map_each_in_place(move |encoded| Self::decode_single(encoded, exponents))
226226
}
227227

228+
fn decode_into(encoded: &[Self::ALPInt], exponents: Exponents, output: &mut [Self]) {
229+
assert_eq!(encoded.len(), output.len());
230+
231+
for i in 0..encoded.len() {
232+
output[i] = Self::decode_single(encoded[i], exponents)
233+
}
234+
}
235+
228236
fn decode_slice_inplace(encoded: &mut [Self::ALPInt], exponents: Exponents) {
229237
let decoded: &mut [Self] = unsafe { transmute(encoded) };
230238
decoded.iter_mut().for_each(|v| {

encodings/fastlanes/src/bitpacking/array/bitpack_decompress.rs

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,27 @@ use vortex_array::arrays::PrimitiveArray;
88
use vortex_array::builders::{ArrayBuilder, PrimitiveBuilder, UninitRange};
99
use vortex_array::patches::Patches;
1010
use vortex_dtype::{
11-
IntegerPType, NativePType, PhysicalPType, match_each_integer_ptype,
12-
match_each_unsigned_integer_ptype,
11+
IntegerPType, NativePType, match_each_integer_ptype, match_each_unsigned_integer_ptype,
1312
};
1413
use vortex_error::VortexExpect;
1514
use vortex_mask::Mask;
1615
use vortex_scalar::Scalar;
1716

1817
use crate::BitPackedArray;
19-
use crate::unpack_iter::{BitPacked, UnpackStrategy};
20-
21-
/// BitPacking strategy - uses plain bitpacking without reference value
22-
pub struct BitPackingStrategy;
23-
24-
impl<T: PhysicalPType<Physical: BitPacking>> UnpackStrategy<T> for BitPackingStrategy {
25-
#[inline(always)]
26-
unsafe fn unpack_chunk(
27-
&self,
28-
bit_width: usize,
29-
chunk: &[T::Physical],
30-
dst: &mut [T::Physical],
31-
) {
32-
// SAFETY: Caller must ensure [`BitPacking::unchecked_unpack`] safety requirements hold.
33-
unsafe {
34-
BitPacking::unchecked_unpack(bit_width, chunk, dst);
35-
}
36-
}
37-
}
18+
use crate::unpack_iter::BitPacked;
3819

39-
pub fn unpack(array: &BitPackedArray) -> PrimitiveArray {
40-
match_each_integer_ptype!(array.ptype(), |P| { unpack_primitive::<P>(array) })
20+
pub fn unpack_array(array: &BitPackedArray) -> PrimitiveArray {
21+
match_each_integer_ptype!(array.ptype(), |P| { unpack_primitive_array::<P>(array) })
4122
}
4223

43-
pub fn unpack_primitive<T: BitPacked>(array: &BitPackedArray) -> PrimitiveArray {
24+
pub fn unpack_primitive_array<T: BitPacked>(array: &BitPackedArray) -> PrimitiveArray {
4425
let mut builder = PrimitiveBuilder::with_capacity(array.dtype().nullability(), array.len());
45-
unpack_into::<T>(array, &mut builder);
26+
unpack_into_primitive_builder::<T>(array, &mut builder);
4627
assert_eq!(builder.len(), array.len());
4728
builder.finish_into_primitive()
4829
}
4930

50-
pub(crate) fn unpack_into<T: BitPacked>(
31+
pub(crate) fn unpack_into_primitive_builder<T: BitPacked>(
5132
array: &BitPackedArray,
5233
// TODO(ngates): do we want to use fastlanes alignment for this buffer?
5334
builder: &mut PrimitiveBuilder<T>,
@@ -65,25 +46,28 @@ pub(crate) fn unpack_into<T: BitPacked>(
6546
uninit_range.append_mask(array.validity_mask());
6647
}
6748

49+
// SAFETY: `decode_into` will initialize all values in this range.
50+
let uninit_slice = unsafe { uninit_range.slice_uninit_mut(0, array.len()) };
51+
6852
let mut bit_packed_iter = array.unpacked_chunks();
69-
bit_packed_iter.decode_into(&mut uninit_range);
53+
bit_packed_iter.decode_into(uninit_slice);
7054

7155
if let Some(patches) = array.patches() {
72-
apply_patches(&mut uninit_range, patches);
56+
apply_patches_to_uninit_range(&mut uninit_range, patches);
7357
};
7458

7559
// SAFETY: We have set a correct validity mask via `append_mask` with `array.len()` values and
76-
// initialized the same number of values needed via calls to `copy_from_slice`.
60+
// initialized the same number of values needed via `decode_into`.
7761
unsafe {
7862
uninit_range.finish();
7963
}
8064
}
8165

82-
pub fn apply_patches<T: NativePType>(dst: &mut UninitRange<T>, patches: &Patches) {
83-
apply_patches_fn(dst, patches, |x| x)
66+
pub fn apply_patches_to_uninit_range<T: NativePType>(dst: &mut UninitRange<T>, patches: &Patches) {
67+
apply_patches_to_uninit_range_fn(dst, patches, |x| x)
8468
}
8569

86-
pub fn apply_patches_fn<T: NativePType, F: Fn(T) -> T>(
70+
pub fn apply_patches_to_uninit_range_fn<T: NativePType, F: Fn(T) -> T>(
8771
dst: &mut UninitRange<T>,
8872
patches: &Patches,
8973
f: F,
@@ -96,7 +80,7 @@ pub fn apply_patches_fn<T: NativePType, F: Fn(T) -> T>(
9680
let values = values.as_slice::<T>();
9781

9882
match_each_unsigned_integer_ptype!(indices.ptype(), |P| {
99-
insert_values_and_validity_at_indices(
83+
insert_values_and_validity_at_indices_to_uninit_range(
10084
dst,
10185
indices.as_slice::<P>(),
10286
values,
@@ -107,7 +91,11 @@ pub fn apply_patches_fn<T: NativePType, F: Fn(T) -> T>(
10791
});
10892
}
10993

110-
fn insert_values_and_validity_at_indices<T: NativePType, IndexT: IntegerPType, F: Fn(T) -> T>(
94+
fn insert_values_and_validity_at_indices_to_uninit_range<
95+
T: NativePType,
96+
IndexT: IntegerPType,
97+
F: Fn(T) -> T,
98+
>(
11199
dst: &mut UninitRange<T>,
112100
indices: &[IndexT],
113101
values: &[T],
@@ -223,23 +211,23 @@ mod tests {
223211
fn test_all_zeros() {
224212
let zeros = buffer![0u16, 0, 0, 0].into_array().to_primitive();
225213
let bitpacked = bitpack_encode(&zeros, 0, None).unwrap();
226-
let actual = unpack(&bitpacked);
214+
let actual = unpack_array(&bitpacked);
227215
assert_arrays_eq!(actual, PrimitiveArray::from_iter([0u16, 0, 0, 0]));
228216
}
229217

230218
#[test]
231219
fn test_simple_patches() {
232220
let zeros = buffer![0u16, 1, 0, 1].into_array().to_primitive();
233221
let bitpacked = bitpack_encode(&zeros, 0, None).unwrap();
234-
let actual = unpack(&bitpacked);
222+
let actual = unpack_array(&bitpacked);
235223
assert_arrays_eq!(actual, PrimitiveArray::from_iter([0u16, 1, 0, 1]));
236224
}
237225

238226
#[test]
239227
fn test_one_full_chunk() {
240228
let zeros = BufferMut::from_iter(0u16..1024).into_array().to_primitive();
241229
let bitpacked = bitpack_encode(&zeros, 10, None).unwrap();
242-
let actual = unpack(&bitpacked);
230+
let actual = unpack_array(&bitpacked);
243231
assert_arrays_eq!(actual, PrimitiveArray::from_iter(0u16..1024));
244232
}
245233

@@ -250,7 +238,7 @@ mod tests {
250238
.to_primitive();
251239
let bitpacked = bitpack_encode(&zeros, 10, None).unwrap();
252240
assert!(bitpacked.patches().is_some());
253-
let actual = unpack(&bitpacked);
241+
let actual = unpack_array(&bitpacked);
254242
assert_arrays_eq!(
255243
actual,
256244
PrimitiveArray::from_iter((5u16..1029).chain(5u16..1029).chain(5u16..1029))
@@ -262,7 +250,7 @@ mod tests {
262250
let zeros = BufferMut::from_iter(0u16..1025).into_array().to_primitive();
263251
let bitpacked = bitpack_encode(&zeros, 11, None).unwrap();
264252
assert!(bitpacked.patches().is_none());
265-
let actual = unpack(&bitpacked);
253+
let actual = unpack_array(&bitpacked);
266254
assert_arrays_eq!(actual, PrimitiveArray::from_iter(0u16..1025));
267255
}
268256

@@ -274,7 +262,7 @@ mod tests {
274262
let bitpacked = bitpack_encode(&zeros, 10, None).unwrap();
275263
assert_eq!(bitpacked.len(), 1025);
276264
assert!(bitpacked.patches().is_some());
277-
let actual = unpack(&bitpacked);
265+
let actual = unpack_array(&bitpacked);
278266
assert_arrays_eq!(actual, PrimitiveArray::from_iter(512u16..1537));
279267
}
280268

@@ -287,7 +275,7 @@ mod tests {
287275
assert_eq!(bitpacked.len(), 1025);
288276
assert!(bitpacked.patches().is_some());
289277
let bitpacked = bitpacked.slice(1023..1025);
290-
let actual = unpack(bitpacked.as_::<BitPackedVTable>());
278+
let actual = unpack_array(bitpacked.as_::<BitPackedVTable>());
291279
assert_arrays_eq!(actual, PrimitiveArray::from_iter([1535u16, 1536]));
292280
}
293281

@@ -300,7 +288,7 @@ mod tests {
300288
assert_eq!(bitpacked.len(), 2229);
301289
assert!(bitpacked.patches().is_some());
302290
let bitpacked = bitpacked.slice(1023..2049);
303-
let actual = unpack(bitpacked.as_::<BitPackedVTable>());
291+
let actual = unpack_array(bitpacked.as_::<BitPackedVTable>());
304292
assert_arrays_eq!(
305293
actual,
306294
PrimitiveArray::from_iter((1023u16..2049).map(|x| x + 512))
@@ -313,7 +301,7 @@ mod tests {
313301
let bitpacked = bitpack_encode(&empty, 0, None).unwrap();
314302

315303
let mut builder = PrimitiveBuilder::<u32>::new(Nullability::NonNullable);
316-
unpack_into(&bitpacked, &mut builder);
304+
unpack_into_primitive_builder(&bitpacked, &mut builder);
317305

318306
let result = builder.finish_into_primitive();
319307
assert_eq!(
@@ -336,7 +324,7 @@ mod tests {
336324

337325
// Unpack into a new builder.
338326
let mut builder = PrimitiveBuilder::<u32>::with_capacity(Nullability::Nullable, 5);
339-
unpack_into(&bitpacked, &mut builder);
327+
unpack_into_primitive_builder(&bitpacked, &mut builder);
340328

341329
let result = builder.finish_into_primitive();
342330

@@ -367,7 +355,7 @@ mod tests {
367355

368356
// Unpack into a new builder.
369357
let mut builder = PrimitiveBuilder::<u32>::with_capacity(Nullability::NonNullable, 100);
370-
unpack_into(&bitpacked, &mut builder);
358+
unpack_into_primitive_builder(&bitpacked, &mut builder);
371359

372360
let result = builder.finish_into_primitive();
373361

encodings/fastlanes/src/bitpacking/array/unpack_iter.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ use lending_iterator::gat;
99
use lending_iterator::prelude::Item;
1010
#[gat(Item)]
1111
use lending_iterator::prelude::LendingIterator;
12-
use vortex_array::builders::UninitRange;
1312
use vortex_buffer::ByteBuffer;
1413
use vortex_dtype::PhysicalPType;
1514

1615
use crate::BitPackedArray;
17-
use crate::bitpacking::bitpack_decompress::BitPackingStrategy;
1816

1917
const CHUNK_SIZE: usize = 1024;
2018

@@ -28,6 +26,24 @@ pub trait UnpackStrategy<T: PhysicalPType> {
2826
unsafe fn unpack_chunk(&self, bit_width: usize, chunk: &[T::Physical], dst: &mut [T::Physical]);
2927
}
3028

29+
/// BitPacking strategy - uses plain bitpacking without reference value
30+
pub struct BitPackingStrategy;
31+
32+
impl<T: PhysicalPType<Physical: BitPacking>> UnpackStrategy<T> for BitPackingStrategy {
33+
#[inline(always)]
34+
unsafe fn unpack_chunk(
35+
&self,
36+
bit_width: usize,
37+
chunk: &[T::Physical],
38+
dst: &mut [T::Physical],
39+
) {
40+
// SAFETY: Caller must ensure [`BitPacking::unchecked_unpack`] safety requirements hold.
41+
unsafe {
42+
BitPacking::unchecked_unpack(bit_width, chunk, dst);
43+
}
44+
}
45+
}
46+
3147
/// Accessor to unpacked chunks of bitpacked arrays
3248
///
3349
/// The usual pattern of usage should follow
@@ -159,29 +175,38 @@ impl<T: PhysicalPType, S: UnpackStrategy<T>> UnpackedChunks<T, S> {
159175

160176
/// Decode all chunks (initial, full, and trailer) into the output range.
161177
/// This consolidates the logic for handling all three chunk types in one place.
162-
pub fn decode_into(&mut self, output: &mut UninitRange<T>) {
178+
pub fn decode_into(&mut self, output: &mut [MaybeUninit<T>]) {
163179
let mut local_idx = 0;
164180

165181
// Handle initial partial chunk if present
166182
if let Some(initial) = self.initial() {
167-
output.copy_from_slice(0, initial);
168183
local_idx = initial.len();
184+
185+
// TODO(connor): use `maybe_uninit_write_slice` feature when it gets stabilized.
186+
// https://github.com/rust-lang/rust/issues/79995
187+
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
188+
let init_initial: &[MaybeUninit<T>] = unsafe { mem::transmute(initial) };
189+
output[..local_idx].copy_from_slice(init_initial);
169190
}
170191

171192
// Handle full chunks
172193
local_idx = self.decode_full_chunks_into_at(output, local_idx);
173194

174195
// Handle trailing partial chunk if present
175196
if let Some(trailer) = self.trailer() {
176-
output.copy_from_slice(local_idx, trailer);
197+
// TODO(connor): use `maybe_uninit_write_slice` feature when it gets stabilized.
198+
// https://github.com/rust-lang/rust/issues/79995
199+
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
200+
let init_trailer: &[MaybeUninit<T>] = unsafe { mem::transmute(trailer) };
201+
output[local_idx..][..init_trailer.len()].copy_from_slice(init_trailer);
177202
}
178203
}
179204

180205
/// Unpack full chunks into output range starting at the given index.
181206
/// Returns the next local index to write to.
182207
fn decode_full_chunks_into_at(
183208
&mut self,
184-
output: &mut UninitRange<T>,
209+
output: &mut [MaybeUninit<T>],
185210
start_idx: usize,
186211
) -> usize {
187212
// If there's only one chunk it has been handled already by `initial` method
@@ -204,8 +229,7 @@ impl<T: PhysicalPType, S: UnpackStrategy<T>> UnpackedChunks<T, S> {
204229
let chunk = &packed_slice[i * elems_per_chunk..][..elems_per_chunk];
205230

206231
unsafe {
207-
// SAFETY: We're about to initialize CHUNK_SIZE elements at local_idx.
208-
let uninit_dst = output.slice_uninit_mut(local_idx, CHUNK_SIZE);
232+
let uninit_dst = &mut output[local_idx..local_idx + CHUNK_SIZE];
209233
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout
210234
let dst: &mut [T::Physical] = mem::transmute(uninit_dst);
211235
self.strategy.unpack_chunk(self.bit_width, chunk, dst);

encodings/fastlanes/src/bitpacking/vtable/canonical.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ use vortex_array::vtable::CanonicalVTable;
77
use vortex_dtype::match_each_integer_ptype;
88
use vortex_error::VortexExpect;
99

10-
use crate::bitpack_decompress::{unpack, unpack_into};
10+
use crate::bitpack_decompress::{unpack_array, unpack_into_primitive_builder};
1111
use crate::{BitPackedArray, BitPackedVTable};
1212

1313
impl CanonicalVTable<BitPackedVTable> for BitPackedVTable {
1414
fn canonicalize(array: &BitPackedArray) -> Canonical {
15-
Canonical::Primitive(unpack(array))
15+
Canonical::Primitive(unpack_array(array))
1616
}
1717

1818
fn append_to_builder(array: &BitPackedArray, builder: &mut dyn ArrayBuilder) {
1919
match_each_integer_ptype!(array.ptype(), |T| {
20-
unpack_into::<T>(
20+
unpack_into_primitive_builder::<T>(
2121
array,
2222
builder
2323
.as_any_mut()

encodings/fastlanes/src/for/compress.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,25 @@ fn fused_decompress<T: PhysicalPType<Physical = T> + UnsignedPType + FoR + Wrapp
124124

125125
let mut builder = PrimitiveBuilder::<T>::with_capacity(for_.dtype().nullability(), bp.len());
126126
let mut uninit_range = builder.uninit_range(bp.len());
127-
128-
// Decode all chunks (initial, full, and trailer) in one call
129-
unpacked.decode_into(&mut uninit_range);
130-
131127
unsafe {
132128
// Append a dense null Mask.
133129
uninit_range.append_mask(bp.validity_mask());
134130
}
135131

132+
// SAFETY: `decode_into` will initialize all values in this range.
133+
let uninit_slice = unsafe { uninit_range.slice_uninit_mut(0, bp.len()) };
134+
135+
// Decode all chunks (initial, full, and trailer) in one call
136+
unpacked.decode_into(uninit_slice);
137+
136138
if let Some(patches) = bp.patches() {
137-
bitpack_decompress::apply_patches_fn(&mut uninit_range, patches, |v| v.wrapping_add(&ref_));
139+
bitpack_decompress::apply_patches_to_uninit_range_fn(&mut uninit_range, patches, |v| {
140+
v.wrapping_add(&ref_)
141+
});
138142
};
139143

144+
// SAFETY: We have set a correct validity mask via `append_mask` with `array.len()` values and
145+
// initialized the same number of values needed via `decode_into`.
140146
unsafe {
141147
uninit_range.finish();
142148
}

0 commit comments

Comments
 (0)