@@ -64,108 +64,19 @@ impl ValidityChild<Patched> for Patched {
6464
6565#[ derive( Clone , prost:: Message ) ]
6666pub 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
17182impl 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