Skip to content

Commit afe2d51

Browse files
committed
bring back old PatchedMetadata
Signed-off-by: Andrew Duffy <andrew@a10y.dev>
1 parent 2ce0cc5 commit afe2d51

File tree

1 file changed

+16
-225
lines changed
  • vortex-array/src/arrays/patched/vtable

1 file changed

+16
-225
lines changed

vortex-array/src/arrays/patched/vtable/mod.rs

Lines changed: 16 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -64,108 +64,19 @@ impl ValidityChild<Patched> for Patched {
6464

6565
#[derive(Clone, prost::Message)]
6666
pub struct PatchedMetadata {
67-
/// A bitfield packed into a single u64 containing all the metadata needed to decode a
68-
/// serialized `PatchedArray`.
69-
///
70-
/// See [`PatchedMetadataFields`].
71-
#[prost(uint64, tag = "1")]
72-
pub(crate) packed: u64,
73-
}
74-
75-
/// A bitfield implemented on top of a `u64` containing the necessary metadata for reading a
76-
/// serialized `PatchedArray`.
77-
///
78-
/// The bit fields are in the following order:
79-
///
80-
/// * `offset`: 10 bits (always < 1024). An offset into the first chunk's patches that should be
81-
/// considered in-view.
82-
/// * `n_lanes_exp`: 3 bits. The binary exponent of `n_lanes`, which must be a power of two.
83-
/// A stored value of 0b000 represents n_lanes=1, and 0b111 represents n_lanes=128.
84-
/// * `n_patches`: 23 bits. The number of total patches, and the length of the indices and values
85-
/// child arrays.
86-
///
87-
/// The remaining bits 36..64 are reserved for future use.
88-
pub(crate) struct PatchedMetadataFields(u64);
89-
90-
impl std::fmt::Debug for PatchedMetadataFields {
91-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92-
f.debug_struct("PatchedMetadataFields")
93-
.field("offset", &self.offset())
94-
.field("n_lanes", &self.n_lanes())
95-
.field("n_patches", &self.n_patches())
96-
.finish()
97-
}
98-
}
99-
100-
impl PatchedMetadataFields {
101-
const OFFSET_BITS: u32 = 10;
102-
const N_LANES_EXP_BITS: u32 = 3;
103-
const N_PATCHES_BITS: u32 = 23;
67+
/// The total number of patches, and the length of the indices and values child arrays.
68+
#[prost(uint32, tag = "1")]
69+
pub(crate) n_patches: u32,
10470

105-
const OFFSET_MASK: u64 = (1 << Self::OFFSET_BITS) - 1;
106-
const N_LANES_EXP_MASK: u64 = (1 << Self::N_LANES_EXP_BITS) - 1;
107-
const N_PATCHES_MASK: u64 = (1 << Self::N_PATCHES_BITS) - 1;
71+
/// The number of lanes used for patch indexing. Must be a power of two between 1 and 128.
72+
#[prost(uint32, tag = "2")]
73+
pub(crate) n_lanes: u32,
10874

109-
const OFFSET_SHIFT: u32 = 0;
110-
const N_LANES_EXP_SHIFT: u32 = Self::OFFSET_BITS;
111-
const N_PATCHES_SHIFT: u32 = Self::OFFSET_BITS + Self::N_LANES_EXP_BITS;
112-
113-
/// Create a new `PatchedMetadataFields` from the component values.
114-
///
115-
/// # Errors
75+
/// An offset into the first chunk's patches that should be considered in-view.
11676
///
117-
/// Returns an error if any value exceeds its bit width:
118-
/// - `offset` must be < 1024 (10 bits)
119-
/// - `n_lanes` must be a power of two between 1 and 128 inclusive
120-
/// - `n_patches` must be < 8388608 (23 bits)
121-
pub fn new(offset: usize, n_lanes: usize, n_patches: usize) -> VortexResult<Self> {
122-
vortex_ensure!(
123-
offset < (1 << Self::OFFSET_BITS),
124-
"offset must be < 1024, got {offset}"
125-
);
126-
vortex_ensure!(
127-
n_lanes.is_power_of_two() && n_lanes <= 128,
128-
"n_lanes must be a power of two between 1 and 128, got {n_lanes}"
129-
);
130-
vortex_ensure!(
131-
n_patches < (1 << Self::N_PATCHES_BITS),
132-
"n_patches must be < 8388608, got {n_patches}"
133-
);
134-
135-
let n_lanes_exp = n_lanes.trailing_zeros() as u64;
136-
137-
let flags = (offset as u64)
138-
| (n_lanes_exp << Self::N_LANES_EXP_SHIFT)
139-
| ((n_patches as u64) << Self::N_PATCHES_SHIFT);
140-
Ok(Self(flags))
141-
}
142-
143-
/// Extract the offset field (bits 0..10).
144-
pub fn offset(&self) -> usize {
145-
((self.0 >> Self::OFFSET_SHIFT) & Self::OFFSET_MASK) as usize
146-
}
147-
148-
/// Extract the n_lanes field (bits 10..13), converted from the stored exponent.
149-
pub fn n_lanes(&self) -> usize {
150-
let exp = (self.0 >> Self::N_LANES_EXP_SHIFT) & Self::N_LANES_EXP_MASK;
151-
1 << exp
152-
}
153-
154-
/// Extract the n_patches field (bits 13..36).
155-
pub fn n_patches(&self) -> usize {
156-
((self.0 >> Self::N_PATCHES_SHIFT) & Self::N_PATCHES_MASK) as usize
157-
}
158-
159-
/// Return the underlying u64 representation.
160-
pub fn into_inner(self) -> u64 {
161-
self.0
162-
}
163-
}
164-
165-
impl From<u64> for PatchedMetadataFields {
166-
fn from(value: u64) -> Self {
167-
Self(value)
168-
}
77+
/// Always between 0 and 1023.
78+
#[prost(uint32, tag = "3")]
79+
pub(crate) offset: u32,
16980
}
17081

17182
impl VTable for Patched {
@@ -251,10 +162,10 @@ impl VTable for Patched {
251162
}
252163

253164
fn metadata(array: &Self::Array) -> VortexResult<Self::Metadata> {
254-
let fields = PatchedMetadataFields::new(array.offset, array.n_lanes, array.indices.len())?;
255-
256165
Ok(ProstMetadata(PatchedMetadata {
257-
packed: fields.into_inner(),
166+
n_patches: u32::try_from(array.indices.len())?,
167+
n_lanes: u32::try_from(array.n_lanes)?,
168+
offset: u32::try_from(array.offset)?,
258169
}))
259170
}
260171

@@ -334,10 +245,9 @@ impl VTable for Patched {
334245
_buffers: &[BufferHandle],
335246
children: &dyn ArrayChildren,
336247
) -> VortexResult<PatchedArray> {
337-
let fields = PatchedMetadataFields::from(metadata.packed);
338-
let offset = fields.offset();
339-
let n_lanes = fields.n_lanes();
340-
let n_patches = fields.n_patches();
248+
let n_patches = metadata.n_patches as usize;
249+
let n_lanes = metadata.n_lanes as usize;
250+
let offset = metadata.offset as usize;
341251

342252
// n_chunks should correspond to the chunk in the `inner`.
343253
// After slicing when offset > 0, there may be additional chunks.
@@ -817,123 +727,4 @@ mod tests {
817727

818728
Ok(())
819729
}
820-
821-
mod metadata_fields_tests {
822-
use vortex_error::VortexResult;
823-
824-
use super::super::PatchedMetadataFields;
825-
826-
#[test]
827-
fn test_roundtrip_min_values() -> VortexResult<()> {
828-
let fields = PatchedMetadataFields::new(0, 1, 0)?;
829-
assert_eq!(fields.offset(), 0);
830-
assert_eq!(fields.n_lanes(), 1);
831-
assert_eq!(fields.n_patches(), 0);
832-
assert_eq!(fields.into_inner(), 0);
833-
Ok(())
834-
}
835-
836-
#[test]
837-
fn test_roundtrip_typical_values() -> VortexResult<()> {
838-
let fields = PatchedMetadataFields::new(512, 16, 1000)?;
839-
assert_eq!(fields.offset(), 512);
840-
assert_eq!(fields.n_lanes(), 16);
841-
assert_eq!(fields.n_patches(), 1000);
842-
Ok(())
843-
}
844-
845-
#[test]
846-
fn test_roundtrip_max_values() -> VortexResult<()> {
847-
let max_offset = (1 << 10) - 1; // 1023
848-
let max_n_lanes = 128; // 2^7
849-
let max_n_patches = (1 << 23) - 1; // 8388607
850-
851-
let fields = PatchedMetadataFields::new(max_offset, max_n_lanes, max_n_patches)?;
852-
assert_eq!(fields.offset(), max_offset);
853-
assert_eq!(fields.n_lanes(), max_n_lanes);
854-
assert_eq!(fields.n_patches(), max_n_patches);
855-
Ok(())
856-
}
857-
858-
#[test]
859-
fn test_all_valid_n_lanes() -> VortexResult<()> {
860-
for exp in 0..=7 {
861-
let n_lanes = 1 << exp;
862-
let fields = PatchedMetadataFields::new(0, n_lanes, 0)?;
863-
assert_eq!(fields.n_lanes(), n_lanes);
864-
}
865-
Ok(())
866-
}
867-
868-
#[test]
869-
fn test_from_u64() {
870-
// n_lanes=16 means exp=4, stored in bits 10..13
871-
let n_lanes_exp = 4u64; // log2(16)
872-
let raw: u64 = 512 | (n_lanes_exp << 10) | (1000 << 13);
873-
let fields = PatchedMetadataFields::from(raw);
874-
assert_eq!(fields.offset(), 512);
875-
assert_eq!(fields.n_lanes(), 16);
876-
assert_eq!(fields.n_patches(), 1000);
877-
}
878-
879-
#[test]
880-
fn test_offset_overflow() {
881-
let result = PatchedMetadataFields::new(1024, 1, 0);
882-
assert!(result.is_err());
883-
assert!(
884-
result
885-
.unwrap_err()
886-
.to_string()
887-
.contains("offset must be < 1024")
888-
);
889-
}
890-
891-
#[test]
892-
fn test_n_lanes_not_power_of_two() {
893-
let result = PatchedMetadataFields::new(0, 3, 0);
894-
assert!(result.is_err());
895-
assert!(
896-
result
897-
.unwrap_err()
898-
.to_string()
899-
.contains("n_lanes must be a power of two")
900-
);
901-
}
902-
903-
#[test]
904-
fn test_n_lanes_overflow() {
905-
let result = PatchedMetadataFields::new(0, 256, 0);
906-
assert!(result.is_err());
907-
assert!(
908-
result
909-
.unwrap_err()
910-
.to_string()
911-
.contains("n_lanes must be a power of two between 1 and 128")
912-
);
913-
}
914-
915-
#[test]
916-
fn test_n_lanes_zero() {
917-
let result = PatchedMetadataFields::new(0, 0, 0);
918-
assert!(result.is_err());
919-
assert!(
920-
result
921-
.unwrap_err()
922-
.to_string()
923-
.contains("n_lanes must be a power of two")
924-
);
925-
}
926-
927-
#[test]
928-
fn test_n_patches_overflow() {
929-
let result = PatchedMetadataFields::new(0, 1, 1 << 23);
930-
assert!(result.is_err());
931-
assert!(
932-
result
933-
.unwrap_err()
934-
.to_string()
935-
.contains("n_patches must be < 8388608")
936-
);
937-
}
938-
}
939730
}

0 commit comments

Comments
 (0)