@@ -798,6 +798,81 @@ pub fn bitmap_stats(buf: &[u8]) -> Result<BitmapStats> {
798798 }
799799}
800800
801+ pub fn bitmap_has_all ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> Result < bool > {
802+ if rhs. is_empty ( ) {
803+ return Ok ( true ) ;
804+ }
805+ if lhs. is_empty ( ) {
806+ return Ok ( false ) ;
807+ }
808+
809+ // Both HybridLarge: use stats for early rejection, then check directly on serialized buffers.
810+ if is_hybrid_large ( lhs) && is_hybrid_large ( rhs) {
811+ let lhs_stats = reader:: bitmap_stats ( & lhs[ HYBRID_HEADER_LEN ..] ) ?;
812+ let rhs_stats = reader:: bitmap_stats ( & rhs[ HYBRID_HEADER_LEN ..] ) ?;
813+ if let ( Some ( lhs_min) , Some ( rhs_min) ) = ( lhs_stats. min , rhs_stats. min )
814+ && lhs_min > rhs_min
815+ {
816+ return Ok ( false ) ;
817+ }
818+ if let ( Some ( rhs_max) , Some ( lhs_max) ) = ( rhs_stats. max , lhs_stats. max )
819+ && rhs_max > lhs_max
820+ {
821+ return Ok ( false ) ;
822+ }
823+ if lhs_stats. len < rhs_stats. len {
824+ return Ok ( false ) ;
825+ }
826+ Ok ( reader:: bitmap_has_all (
827+ & lhs[ HYBRID_HEADER_LEN ..] ,
828+ & rhs[ HYBRID_HEADER_LEN ..] ,
829+ ) ?)
830+ } else if is_hybrid_large ( lhs) || is_hybrid_large ( rhs) {
831+ // Mixed path: one side is HybridLarge, the other is HybridSmall or Legacy.
832+ // Use stats for early rejection; if rhs is HybridSmall, iterate and probe lhs;
833+ // otherwise fall back to full deserialization.
834+ let lhs_stats = bitmap_stats ( lhs) ?;
835+ let rhs_stats = bitmap_stats ( rhs) ?;
836+ if let ( Some ( lhs_min) , Some ( rhs_min) ) = ( lhs_stats. min , rhs_stats. min )
837+ && lhs_min > rhs_min
838+ {
839+ return Ok ( false ) ;
840+ }
841+ if let ( Some ( rhs_max) , Some ( lhs_max) ) = ( rhs_stats. max , lhs_stats. max )
842+ && rhs_max > lhs_max
843+ {
844+ return Ok ( false ) ;
845+ }
846+ // lhs.len < rhs.len -> lhs cannot contain all of rhs
847+ if lhs_stats. len < rhs_stats. len {
848+ return Ok ( false ) ;
849+ }
850+ // rhs is HybridSmall: iterate its (≤31) values and probe lhs via bitmap_contains.
851+ // Each bitmap_contains call scans prefix buckets from the start, causing redundant
852+ // work across iterations. This could be improved with a hint/cursor mechanism that
853+ // tracks the last scanned position, but since HybridSmall holds at most 31 values
854+ // the overhead is bounded (~μs-level). Revisit if this path becomes a bottleneck.
855+ if is_hybrid_large ( lhs) && is_hybrid ( rhs) && !is_hybrid_large ( rhs) {
856+ let rhs_bm = deserialize_bitmap ( rhs) ?;
857+ for value in rhs_bm. iter ( ) {
858+ if !bitmap_contains ( lhs, value) ? {
859+ return Ok ( false ) ;
860+ }
861+ }
862+ return Ok ( true ) ;
863+ }
864+ // Fallback to deserialization and is_superset
865+ let lhs_bm = deserialize_bitmap ( lhs) ?;
866+ let rhs_bm = deserialize_bitmap ( rhs) ?;
867+ Ok ( lhs_bm. is_superset ( & rhs_bm) )
868+ } else {
869+ // Both else: deserialize both
870+ let lhs_bm = deserialize_bitmap ( lhs) ?;
871+ let rhs_bm = deserialize_bitmap ( rhs) ?;
872+ Ok ( lhs_bm. is_superset ( & rhs_bm) )
873+ }
874+ }
875+
801876pub fn bitmap_has_any ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> Result < bool > {
802877 if lhs. is_empty ( ) || rhs. is_empty ( ) {
803878 return Ok ( false ) ;
@@ -1893,4 +1968,204 @@ mod tests {
18931968 assert_eq ! ( stats. min, Some ( 42 ) ) ;
18941969 assert_eq ! ( stats. max, Some ( 100 ) ) ;
18951970 }
1971+
1972+ fn ground_truth_has_all ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> bool {
1973+ let lhs_bm = deserialize_bitmap ( lhs) . unwrap ( ) ;
1974+ let rhs_bm = deserialize_bitmap ( rhs) . unwrap ( ) ;
1975+ lhs_bm. is_superset ( & rhs_bm)
1976+ }
1977+
1978+ #[ test]
1979+ fn test_bitmap_has_all ( ) {
1980+ // Both HybridLarge, rhs is subset: 0..50000 contains 0..10000
1981+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
1982+ let rhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
1983+ let mut lhs_buf = Vec :: new ( ) ;
1984+ let mut rhs_buf = Vec :: new ( ) ;
1985+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
1986+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
1987+ assert_eq ! (
1988+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
1989+ ground_truth_has_all( & lhs_buf, & rhs_buf)
1990+ ) ;
1991+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
1992+
1993+ // Both HybridLarge, rhs is not subset: 0..50000 vs 40000..90000
1994+ // rhs has values 50000-89999 that are not in lhs
1995+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
1996+ let rhs = HybridBitmap :: from_iter ( 40000u64 ..90000 ) ;
1997+ let mut lhs_buf = Vec :: new ( ) ;
1998+ let mut rhs_buf = Vec :: new ( ) ;
1999+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2000+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2001+ assert_eq ! (
2002+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2003+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2004+ ) ;
2005+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2006+
2007+ // Both HybridLarge, disjoint: 0..50000 vs 100000..150000
2008+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2009+ let rhs = HybridBitmap :: from_iter ( 100000u64 ..150000 ) ;
2010+ let mut lhs_buf = Vec :: new ( ) ;
2011+ let mut rhs_buf = Vec :: new ( ) ;
2012+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2013+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2014+ assert_eq ! (
2015+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2016+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2017+ ) ;
2018+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2019+
2020+ // Both HybridSmall, rhs is subset: 0..31 contains 5..15
2021+ let lhs = HybridBitmap :: from_iter ( 0u64 ..31 ) ;
2022+ let rhs = HybridBitmap :: from_iter ( 5u64 ..15 ) ;
2023+ let mut lhs_buf = Vec :: new ( ) ;
2024+ let mut rhs_buf = Vec :: new ( ) ;
2025+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2026+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2027+ assert_eq ! (
2028+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2029+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2030+ ) ;
2031+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2032+
2033+ // Both HybridSmall, rhs is not subset: 0..15 vs 10..25
2034+ // rhs has values 15-24 that are not in lhs
2035+ let lhs = HybridBitmap :: from_iter ( 0u64 ..15 ) ;
2036+ let rhs = HybridBitmap :: from_iter ( 10u64 ..25 ) ;
2037+ let mut lhs_buf = Vec :: new ( ) ;
2038+ let mut rhs_buf = Vec :: new ( ) ;
2039+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2040+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2041+ assert_eq ! (
2042+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2043+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2044+ ) ;
2045+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2046+
2047+ // Mixed (HybridLarge lhs, HybridSmall rhs) with superset: 0..50000 contains 5..15
2048+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2049+ let rhs = HybridBitmap :: from_iter ( 5u64 ..15 ) ;
2050+ let mut lhs_buf = Vec :: new ( ) ;
2051+ let mut rhs_buf = Vec :: new ( ) ;
2052+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2053+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2054+ assert_eq ! (
2055+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2056+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2057+ ) ;
2058+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2059+
2060+ // Mixed (HybridLarge lhs, HybridSmall rhs not subset): 0..50000 vs 49990..50010
2061+ // rhs has values 50000-50009 that are not in lhs
2062+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2063+ let rhs = HybridBitmap :: from_iter ( 49990u64 ..50010 ) ;
2064+ let mut lhs_buf = Vec :: new ( ) ;
2065+ let mut rhs_buf = Vec :: new ( ) ;
2066+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2067+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2068+ assert_eq ! (
2069+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2070+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2071+ ) ;
2072+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2073+
2074+ // Mixed (HybridSmall lhs, HybridLarge rhs): already rejected by len fast path
2075+ let lhs = HybridBitmap :: from_iter ( 0u64 ..31 ) ;
2076+ let rhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2077+ let mut lhs_buf = Vec :: new ( ) ;
2078+ let mut rhs_buf = Vec :: new ( ) ;
2079+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2080+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2081+ assert_eq ! (
2082+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2083+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2084+ ) ;
2085+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2086+
2087+ // Empty rhs: always true
2088+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2089+ let mut lhs_buf = Vec :: new ( ) ;
2090+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2091+ assert ! ( bitmap_has_all( & lhs_buf, & [ ] ) . unwrap( ) ) ;
2092+
2093+ // Empty lhs with non-empty rhs: always false
2094+ let rhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2095+ let mut rhs_buf = Vec :: new ( ) ;
2096+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2097+ assert ! ( !bitmap_has_all( & [ ] , & rhs_buf) . unwrap( ) ) ;
2098+
2099+ // Both empty: true
2100+ assert ! ( bitmap_has_all( & [ ] , & [ ] ) . unwrap( ) ) ;
2101+
2102+ // Mixed (Legacy lhs, HybridLarge rhs)
2103+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2104+ for v in 0u64 ..50000 {
2105+ lhs_tree. insert ( v) ;
2106+ }
2107+ let rhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
2108+ let mut lhs_buf = Vec :: new ( ) ;
2109+ let mut rhs_buf = Vec :: new ( ) ;
2110+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2111+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2112+ assert_eq ! (
2113+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2114+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2115+ ) ;
2116+
2117+ // Mixed (HybridLarge lhs, Legacy rhs)
2118+ let lhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
2119+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2120+ for v in 0u64 ..50000 {
2121+ rhs_tree. insert ( v) ;
2122+ }
2123+
2124+ let mut lhs_buf = Vec :: new ( ) ;
2125+ let mut rhs_buf = Vec :: new ( ) ;
2126+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2127+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2128+ assert_eq ! (
2129+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2130+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2131+ ) ;
2132+
2133+ // Both Legacy
2134+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2135+ for v in 0u64 ..100 {
2136+ lhs_tree. insert ( v) ;
2137+ }
2138+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2139+ for v in 50u64 ..80 {
2140+ rhs_tree. insert ( v) ;
2141+ }
2142+ let mut lhs_buf = Vec :: new ( ) ;
2143+ let mut rhs_buf = Vec :: new ( ) ;
2144+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2145+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2146+ assert_eq ! (
2147+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2148+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2149+ ) ;
2150+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2151+
2152+ // Both Legacy, rhs not subset
2153+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2154+ for v in 0u64 ..100 {
2155+ lhs_tree. insert ( v) ;
2156+ }
2157+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2158+ for v in 50u64 ..150 {
2159+ rhs_tree. insert ( v) ;
2160+ }
2161+ let mut lhs_buf = Vec :: new ( ) ;
2162+ let mut rhs_buf = Vec :: new ( ) ;
2163+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2164+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2165+ assert_eq ! (
2166+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2167+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2168+ ) ;
2169+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2170+ }
18962171}
0 commit comments