@@ -29,113 +29,108 @@ use std::hash::{Hash, Hasher};
2929use super :: result:: build_in_list_result;
3030use super :: static_filter:: { StaticFilter , handle_dictionary} ;
3131
32- /// Bitmap filter for O(1) set membership via single bit test.
33- ///
34- /// `UInt8` has only 256 possible values, so the filter stores membership in a
35- /// 256-bit bitmap instead of using a hash table.
36- pub ( super ) struct UInt8BitmapFilter {
37- null_count : usize ,
38- bits : [ u64 ; 4 ] ,
32+ pub ( super ) trait BitmapStorage : Send + Sync {
33+ fn new_zeroed ( ) -> Self ;
34+ fn set_bit ( & mut self , index : usize ) ;
35+ fn get_bit ( & self , index : usize ) -> bool ;
3936}
4037
41- impl UInt8BitmapFilter {
42- pub ( super ) fn try_new ( in_array : & ArrayRef ) -> Result < Self > {
43- let prim_array = in_array. as_primitive_opt :: < UInt8Type > ( ) . ok_or_else ( || {
44- exec_datafusion_err ! ( "UInt8BitmapFilter: expected UInt8 array" )
45- } ) ?;
46- let mut bits = [ 0u64 ; 4 ] ;
47- let mut set_bit = |v : u8 | {
48- let index = usize:: from ( v) ;
49- bits[ index / 64 ] |= 1u64 << ( index % 64 ) ;
50- } ;
51-
52- let values = prim_array. values ( ) ;
53- match prim_array. nulls ( ) {
54- None => {
55- for & v in values {
56- set_bit ( v) ;
57- }
58- }
59- Some ( nulls) => {
60- for i in
61- BitIndexIterator :: new ( nulls. validity ( ) , nulls. offset ( ) , nulls. len ( ) )
62- {
63- set_bit ( values[ i] ) ;
64- }
65- }
66- }
67- Ok ( Self {
68- null_count : prim_array. null_count ( ) ,
69- bits,
70- } )
38+ impl BitmapStorage for [ u64 ; 4 ] {
39+ #[ inline]
40+ fn new_zeroed ( ) -> Self {
41+ [ 0u64 ; 4 ]
42+ }
43+ #[ inline]
44+ fn set_bit ( & mut self , index : usize ) {
45+ self [ index / 64 ] |= 1u64 << ( index % 64 ) ;
7146 }
47+ #[ inline( always) ]
48+ fn get_bit ( & self , index : usize ) -> bool {
49+ ( self [ index / 64 ] >> ( index % 64 ) ) & 1 != 0
50+ }
51+ }
7252
53+ impl BitmapStorage for Box < [ u64 ; 1024 ] > {
54+ #[ inline]
55+ fn new_zeroed ( ) -> Self {
56+ Box :: new ( [ 0u64 ; 1024 ] )
57+ }
58+ #[ inline]
59+ fn set_bit ( & mut self , index : usize ) {
60+ self [ index / 64 ] |= 1u64 << ( index % 64 ) ;
61+ }
7362 #[ inline( always) ]
74- fn check ( & self , needle : u8 ) -> bool {
75- let index = needle as usize ;
76- ( self . bits [ index / 64 ] >> ( index % 64 ) ) & 1 != 0
63+ fn get_bit ( & self , index : usize ) -> bool {
64+ ( self [ index / 64 ] >> ( index % 64 ) ) & 1 != 0
7765 }
7866}
7967
80- impl StaticFilter for UInt8BitmapFilter {
81- fn null_count ( & self ) -> usize {
82- self . null_count
68+ pub ( super ) trait BitmapFilterConfig : Send + Sync + ' static {
69+ const DATA_TYPE_NAME : & ' static str ;
70+
71+ type Native : ArrowNativeType + Copy + Send + Sync ;
72+ type ArrowType : ArrowPrimitiveType < Native = Self :: Native > ;
73+ type Storage : BitmapStorage ;
74+
75+ fn to_index ( v : Self :: Native ) -> usize ;
76+ }
77+
78+ pub ( super ) enum UInt8BitmapConfig { }
79+ impl BitmapFilterConfig for UInt8BitmapConfig {
80+ const DATA_TYPE_NAME : & ' static str = "UInt8" ;
81+
82+ type Native = u8 ;
83+ type ArrowType = UInt8Type ;
84+ type Storage = [ u64 ; 4 ] ;
85+
86+ #[ inline( always) ]
87+ fn to_index ( v : u8 ) -> usize {
88+ v as usize
8389 }
90+ }
8491
85- fn contains ( & self , v : & dyn Array , negated : bool ) -> Result < BooleanArray > {
86- handle_dictionary ! ( self , v, negated) ;
87- let v = v. as_primitive_opt :: < UInt8Type > ( ) . ok_or_else ( || {
88- exec_datafusion_err ! ( "UInt8BitmapFilter: expected UInt8 array" )
89- } ) ?;
90- let input_values = v. values ( ) ;
91- Ok ( build_in_list_result (
92- v. len ( ) ,
93- v. nulls ( ) ,
94- self . null_count > 0 ,
95- negated,
96- #[ inline( always) ]
97- |i| {
98- // SAFETY: `build_in_list_result` invokes this closure for
99- // indices in `0..v.len()`, which matches `input_values.len()`.
100- let needle = unsafe { * input_values. get_unchecked ( i) } ;
101- self . check ( needle)
102- } ,
103- ) )
92+ pub ( super ) enum UInt16BitmapConfig { }
93+ impl BitmapFilterConfig for UInt16BitmapConfig {
94+ const DATA_TYPE_NAME : & ' static str = "UInt16" ;
95+
96+ type Native = u16 ;
97+ type ArrowType = UInt16Type ;
98+ type Storage = Box < [ u64 ; 1024 ] > ;
99+
100+ #[ inline( always) ]
101+ fn to_index ( v : u16 ) -> usize {
102+ v as usize
104103 }
105104}
106105
107- /// Bitmap filter for O(1) `UInt16` set membership via single bit test.
106+ /// Bitmap filter for O(1) set membership via single bit test.
108107///
109- /// `UInt16` has 65,536 possible values, so the filter stores membership in an
110- /// 8 KiB heap-allocated bitmap instead of using a hash table.
111- pub ( super ) struct UInt16BitmapFilter {
108+ /// Small integer domains can store membership in a fixed-size bitmap instead
109+ /// of using a hash table.
110+ pub ( super ) struct BitmapFilter < C : BitmapFilterConfig > {
112111 null_count : usize ,
113- bits : Box < [ u64 ; 1024 ] > ,
112+ bits : C :: Storage ,
114113}
115114
116- impl UInt16BitmapFilter {
115+ impl < C : BitmapFilterConfig > BitmapFilter < C > {
117116 pub ( super ) fn try_new ( in_array : & ArrayRef ) -> Result < Self > {
118- let prim_array = in_array. as_primitive_opt :: < UInt16Type > ( ) . ok_or_else ( || {
119- exec_datafusion_err ! ( "UInt16BitmapFilter: expected UInt16 array" )
120- } ) ?;
121- let mut bits = Box :: new ( [ 0u64 ; 1024 ] ) ;
122- let mut set_bit = |v : u16 | {
123- let index = usize:: from ( v) ;
124- bits[ index / 64 ] |= 1u64 << ( index % 64 ) ;
125- } ;
126-
117+ let prim_array =
118+ in_array. as_primitive_opt :: < C :: ArrowType > ( ) . ok_or_else ( || {
119+ exec_datafusion_err ! ( "BitmapFilter: expected {} array" , C :: DATA_TYPE_NAME )
120+ } ) ?;
121+ let mut bits = C :: Storage :: new_zeroed ( ) ;
127122 let values = prim_array. values ( ) ;
128123 match prim_array. nulls ( ) {
129124 None => {
130125 for & v in values {
131- set_bit ( v ) ;
126+ bits . set_bit ( C :: to_index ( v ) ) ;
132127 }
133128 }
134129 Some ( nulls) => {
135130 for i in
136131 BitIndexIterator :: new ( nulls. validity ( ) , nulls. offset ( ) , nulls. len ( ) )
137132 {
138- set_bit ( values[ i] ) ;
133+ bits . set_bit ( C :: to_index ( values[ i] ) ) ;
139134 }
140135 }
141136 }
@@ -146,21 +141,20 @@ impl UInt16BitmapFilter {
146141 }
147142
148143 #[ inline( always) ]
149- fn check ( & self , needle : u16 ) -> bool {
150- let index = needle as usize ;
151- ( self . bits [ index / 64 ] >> ( index % 64 ) ) & 1 != 0
144+ fn check ( & self , needle : C :: Native ) -> bool {
145+ self . bits . get_bit ( C :: to_index ( needle) )
152146 }
153147}
154148
155- impl StaticFilter for UInt16BitmapFilter {
149+ impl < C : BitmapFilterConfig > StaticFilter for BitmapFilter < C > {
156150 fn null_count ( & self ) -> usize {
157151 self . null_count
158152 }
159153
160154 fn contains ( & self , v : & dyn Array , negated : bool ) -> Result < BooleanArray > {
161155 handle_dictionary ! ( self , v, negated) ;
162- let v = v. as_primitive_opt :: < UInt16Type > ( ) . ok_or_else ( || {
163- exec_datafusion_err ! ( "UInt16BitmapFilter : expected UInt16 array" )
156+ let v = v. as_primitive_opt :: < C :: ArrowType > ( ) . ok_or_else ( || {
157+ exec_datafusion_err ! ( "BitmapFilter : expected {} array" , C :: DATA_TYPE_NAME )
164158 } ) ?;
165159 let input_values = v. values ( ) ;
166160 Ok ( build_in_list_result (
@@ -406,7 +400,7 @@ mod tests {
406400 #[ test]
407401 fn bitmap_filter_u8_handles_nulls ( ) -> Result < ( ) > {
408402 let haystack: ArrayRef = Arc :: new ( UInt8Array :: from ( vec ! [ Some ( 1 ) , None , Some ( 3 ) ] ) ) ;
409- let filter = UInt8BitmapFilter :: try_new ( & haystack) ?;
403+ let filter = BitmapFilter :: < UInt8BitmapConfig > :: try_new ( & haystack) ?;
410404 let needles = UInt8Array :: from ( vec ! [ Some ( 1 ) , Some ( 2 ) , None , Some ( 3 ) ] ) ;
411405
412406 assert_contains ( & filter, & needles, vec ! [ Some ( true ) , None , None , Some ( true ) ] ) ?;
@@ -421,7 +415,7 @@ mod tests {
421415 #[ test]
422416 fn bitmap_filter_u8_handles_dictionary_needles ( ) -> Result < ( ) > {
423417 let haystack: ArrayRef = Arc :: new ( UInt8Array :: from ( vec ! [ Some ( 1 ) , None , Some ( 3 ) ] ) ) ;
424- let filter = UInt8BitmapFilter :: try_new ( & haystack) ?;
418+ let filter = BitmapFilter :: < UInt8BitmapConfig > :: try_new ( & haystack) ?;
425419
426420 let keys = Int8Array :: from ( vec ! [ Some ( 0 ) , Some ( 1 ) , None , Some ( 2 ) ] ) ;
427421 let values = Arc :: new ( UInt8Array :: from ( vec ! [ Some ( 1 ) , Some ( 2 ) , Some ( 3 ) ] ) ) ;
@@ -438,7 +432,7 @@ mod tests {
438432 Some ( 1024 ) ,
439433 Some ( u16 :: MAX ) ,
440434 ] ) ) ;
441- let filter = UInt16BitmapFilter :: try_new ( & haystack) ?;
435+ let filter = BitmapFilter :: < UInt16BitmapConfig > :: try_new ( & haystack) ?;
442436 let needles =
443437 UInt16Array :: from ( vec ! [ Some ( 0 ) , Some ( 1 ) , Some ( 1024 ) , Some ( u16 :: MAX ) , None ] ) ;
444438
0 commit comments