33
44use std:: ops:: Range ;
55
6+ use vortex_error:: VortexExpect ;
67use vortex_error:: VortexResult ;
78
89use crate :: ArrayRef ;
@@ -12,35 +13,74 @@ use crate::arrays::Constant;
1213use crate :: arrays:: ConstantArray ;
1314use crate :: arrays:: Dict ;
1415use crate :: arrays:: DictArray ;
16+ use crate :: arrays:: Primitive ;
1517use crate :: arrays:: dict:: DictArraySlotsExt ;
1618use crate :: arrays:: slice:: SliceReduce ;
19+ use crate :: expr:: stats:: Precision ;
20+ use crate :: expr:: stats:: Stat ;
1721use crate :: scalar:: Scalar ;
22+ use crate :: scalar:: ScalarValue ;
1823
1924impl SliceReduce for Dict {
2025 fn slice ( array : ArrayView < ' _ , Self > , range : Range < usize > ) -> VortexResult < Option < ArrayRef > > {
21- let sliced_code = array. codes ( ) . slice ( range) ?;
26+ if let Some ( code) = array. codes ( ) . as_opt :: < Constant > ( ) {
27+ return slice_constant_code ( array, code. scalar ( ) , range. len ( ) ) ;
28+ }
29+
30+ let sliced_code = if let Some ( codes) = array. codes ( ) . as_typed :: < Primitive > ( ) {
31+ let sliced_code = <Primitive as SliceReduce >:: slice ( codes, range) ?
32+ . vortex_expect ( "Primitive SliceReduce should always return Some" ) ;
33+ // Because we specialize the primitive branch here, we have to make sure to handle the stat inheritance
34+ inherit_slice_stats ( array. codes ( ) , & sliced_code) ;
35+ sliced_code
36+ } else {
37+ array. codes ( ) . slice ( range) ?
38+ } ;
39+
2240 // TODO(joe): if the range is size 1 replace with a constant array
2341 if let Some ( code) = sliced_code. as_opt :: < Constant > ( ) {
24- let code = code. scalar ( ) . as_primitive ( ) . as_ :: < usize > ( ) ;
25- return if let Some ( code) = code {
26- let values = array. values ( ) . slice ( code..code + 1 ) ?;
27- Ok ( Some (
28- DictArray :: new (
29- ConstantArray :: new ( 0u8 , sliced_code. len ( ) ) . into_array ( ) ,
30- values,
31- )
32- . into_array ( ) ,
33- ) )
34- } else {
35- Ok ( Some (
36- ConstantArray :: new ( Scalar :: null ( array. dtype ( ) . clone ( ) ) , sliced_code. len ( ) )
37- . into_array ( ) ,
38- ) )
39- } ;
42+ return slice_constant_code ( array, code. scalar ( ) , sliced_code. len ( ) ) ;
4043 }
4144 // SAFETY: slicing the codes preserves invariants.
45+ let array =
46+ unsafe { DictArray :: new_unchecked ( sliced_code, array. values ( ) . clone ( ) ) . into_array ( ) } ;
47+
48+ Ok ( Some ( array) )
49+ }
50+ }
51+
52+ fn inherit_slice_stats ( source : & ArrayRef , sliced : & ArrayRef ) {
53+ source. statistics ( ) . with_iter ( |iter| {
54+ sliced
55+ . statistics ( )
56+ . inherit ( iter. filter ( |( stat, value) | is_inheritable_true_slice_stat ( * stat, value) ) ) ;
57+ } ) ;
58+ }
59+
60+ fn is_inheritable_true_slice_stat ( stat : Stat , value : & Precision < ScalarValue > ) -> bool {
61+ matches ! (
62+ stat,
63+ Stat :: IsConstant | Stat :: IsSorted | Stat :: IsStrictSorted
64+ ) && value
65+ . as_ref ( )
66+ . as_exact ( )
67+ . is_some_and ( |value| matches ! ( value, ScalarValue :: Bool ( true ) ) )
68+ }
69+
70+ fn slice_constant_code (
71+ array : ArrayView < ' _ , Dict > ,
72+ code : & Scalar ,
73+ len : usize ,
74+ ) -> VortexResult < Option < ArrayRef > > {
75+ let code = code. as_primitive ( ) . as_ :: < usize > ( ) ;
76+ if let Some ( code) = code {
77+ let values = array. values ( ) . slice ( code..code + 1 ) ?;
78+ Ok ( Some (
79+ DictArray :: new ( ConstantArray :: new ( 0u8 , len) . into_array ( ) , values) . into_array ( ) ,
80+ ) )
81+ } else {
4282 Ok ( Some (
43- unsafe { DictArray :: new_unchecked ( sliced_code , array. values ( ) . clone ( ) ) } . into_array ( ) ,
83+ ConstantArray :: new ( Scalar :: null ( array. dtype ( ) . clone ( ) ) , len ) . into_array ( ) ,
4484 ) )
4585 }
4686}
0 commit comments