@@ -838,6 +838,82 @@ pub fn bitmap_stats(buf: &[u8]) -> Result<BitmapStats> {
838838 }
839839}
840840
841+ pub fn bitmap_has_all ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> Result < bool > {
842+ if rhs. is_empty ( ) {
843+ return Ok ( true ) ;
844+ }
845+ if lhs. is_empty ( ) {
846+ return Ok ( false ) ;
847+ }
848+ validate_serialized_bitmap_header_and_length ( lhs) ?;
849+ validate_serialized_bitmap_header_and_length ( rhs) ?;
850+ // Both HybridLarge: use stats for early rejection, then check directly on serialized buffers.
851+ if is_hybrid_large ( lhs) && is_hybrid_large ( rhs) {
852+ let lhs_stats = reader:: bitmap_stats ( & lhs[ HYBRID_HEADER_LEN ..] ) ?;
853+ let rhs_stats = reader:: bitmap_stats ( & rhs[ HYBRID_HEADER_LEN ..] ) ?;
854+ if let ( Some ( lhs_min) , Some ( rhs_min) ) = ( lhs_stats. min , rhs_stats. min )
855+ && lhs_min > rhs_min
856+ {
857+ return Ok ( false ) ;
858+ }
859+ if let ( Some ( rhs_max) , Some ( lhs_max) ) = ( rhs_stats. max , lhs_stats. max )
860+ && rhs_max > lhs_max
861+ {
862+ return Ok ( false ) ;
863+ }
864+ if lhs_stats. len < rhs_stats. len {
865+ return Ok ( false ) ;
866+ }
867+ Ok ( reader:: bitmap_has_all (
868+ & lhs[ HYBRID_HEADER_LEN ..] ,
869+ & rhs[ HYBRID_HEADER_LEN ..] ,
870+ ) ?)
871+ } else if is_hybrid_large ( lhs) || is_hybrid_large ( rhs) {
872+ // Mixed path: one side is HybridLarge, the other is HybridSmall or Legacy.
873+ // Use stats for early rejection; if rhs is HybridSmall, iterate and probe lhs;
874+ // otherwise fall back to full deserialization.
875+ let lhs_stats = bitmap_stats ( lhs) ?;
876+ let rhs_stats = bitmap_stats ( rhs) ?;
877+ if let ( Some ( lhs_min) , Some ( rhs_min) ) = ( lhs_stats. min , rhs_stats. min )
878+ && lhs_min > rhs_min
879+ {
880+ return Ok ( false ) ;
881+ }
882+ if let ( Some ( rhs_max) , Some ( lhs_max) ) = ( rhs_stats. max , lhs_stats. max )
883+ && rhs_max > lhs_max
884+ {
885+ return Ok ( false ) ;
886+ }
887+ // lhs.len < rhs.len -> lhs cannot contain all of rhs
888+ if lhs_stats. len < rhs_stats. len {
889+ return Ok ( false ) ;
890+ }
891+ // rhs is HybridSmall: iterate its (≤31) values and probe lhs via bitmap_contains.
892+ // Each bitmap_contains call scans prefix buckets from the start, causing redundant
893+ // work across iterations. This could be improved with a hint/cursor mechanism that
894+ // tracks the last scanned position, but since HybridSmall holds at most 31 values
895+ // the overhead is bounded (~μs-level). Revisit if this path becomes a bottleneck.
896+ if is_hybrid_large ( lhs) && is_hybrid ( rhs) && !is_hybrid_large ( rhs) {
897+ let rhs_bm = deserialize_bitmap ( rhs) ?;
898+ for value in rhs_bm. iter ( ) {
899+ if !bitmap_contains ( lhs, value) ? {
900+ return Ok ( false ) ;
901+ }
902+ }
903+ return Ok ( true ) ;
904+ }
905+ // Fallback to deserialization and is_superset
906+ let lhs_bm = deserialize_bitmap ( lhs) ?;
907+ let rhs_bm = deserialize_bitmap ( rhs) ?;
908+ Ok ( lhs_bm. is_superset ( & rhs_bm) )
909+ } else {
910+ // Both else: deserialize both
911+ let lhs_bm = deserialize_bitmap ( lhs) ?;
912+ let rhs_bm = deserialize_bitmap ( rhs) ?;
913+ Ok ( lhs_bm. is_superset ( & rhs_bm) )
914+ }
915+ }
916+
841917pub fn bitmap_has_any ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> Result < bool > {
842918 if lhs. is_empty ( ) || rhs. is_empty ( ) {
843919 return Ok ( false ) ;
@@ -1936,4 +2012,204 @@ mod tests {
19362012 assert_eq ! ( stats. min, Some ( 42 ) ) ;
19372013 assert_eq ! ( stats. max, Some ( 100 ) ) ;
19382014 }
2015+
2016+ fn ground_truth_has_all ( lhs : & [ u8 ] , rhs : & [ u8 ] ) -> bool {
2017+ let lhs_bm = deserialize_bitmap ( lhs) . unwrap ( ) ;
2018+ let rhs_bm = deserialize_bitmap ( rhs) . unwrap ( ) ;
2019+ lhs_bm. is_superset ( & rhs_bm)
2020+ }
2021+
2022+ #[ test]
2023+ fn test_bitmap_has_all ( ) {
2024+ // Both HybridLarge, rhs is subset: 0..50000 contains 0..10000
2025+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2026+ let rhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
2027+ let mut lhs_buf = Vec :: new ( ) ;
2028+ let mut rhs_buf = Vec :: new ( ) ;
2029+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2030+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2031+ assert_eq ! (
2032+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2033+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2034+ ) ;
2035+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2036+
2037+ // Both HybridLarge, rhs is not subset: 0..50000 vs 40000..90000
2038+ // rhs has values 50000-89999 that are not in lhs
2039+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2040+ let rhs = HybridBitmap :: from_iter ( 40000u64 ..90000 ) ;
2041+ let mut lhs_buf = Vec :: new ( ) ;
2042+ let mut rhs_buf = Vec :: new ( ) ;
2043+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2044+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2045+ assert_eq ! (
2046+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2047+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2048+ ) ;
2049+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2050+
2051+ // Both HybridLarge, disjoint: 0..50000 vs 100000..150000
2052+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2053+ let rhs = HybridBitmap :: from_iter ( 100000u64 ..150000 ) ;
2054+ let mut lhs_buf = Vec :: new ( ) ;
2055+ let mut rhs_buf = Vec :: new ( ) ;
2056+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2057+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2058+ assert_eq ! (
2059+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2060+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2061+ ) ;
2062+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2063+
2064+ // Both HybridSmall, rhs is subset: 0..31 contains 5..15
2065+ let lhs = HybridBitmap :: from_iter ( 0u64 ..31 ) ;
2066+ let rhs = HybridBitmap :: from_iter ( 5u64 ..15 ) ;
2067+ let mut lhs_buf = Vec :: new ( ) ;
2068+ let mut rhs_buf = Vec :: new ( ) ;
2069+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2070+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2071+ assert_eq ! (
2072+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2073+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2074+ ) ;
2075+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2076+
2077+ // Both HybridSmall, rhs is not subset: 0..15 vs 10..25
2078+ // rhs has values 15-24 that are not in lhs
2079+ let lhs = HybridBitmap :: from_iter ( 0u64 ..15 ) ;
2080+ let rhs = HybridBitmap :: from_iter ( 10u64 ..25 ) ;
2081+ let mut lhs_buf = Vec :: new ( ) ;
2082+ let mut rhs_buf = Vec :: new ( ) ;
2083+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2084+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2085+ assert_eq ! (
2086+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2087+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2088+ ) ;
2089+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2090+
2091+ // Mixed (HybridLarge lhs, HybridSmall rhs) with superset: 0..50000 contains 5..15
2092+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2093+ let rhs = HybridBitmap :: from_iter ( 5u64 ..15 ) ;
2094+ let mut lhs_buf = Vec :: new ( ) ;
2095+ let mut rhs_buf = Vec :: new ( ) ;
2096+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2097+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2098+ assert_eq ! (
2099+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2100+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2101+ ) ;
2102+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2103+
2104+ // Mixed (HybridLarge lhs, HybridSmall rhs not subset): 0..50000 vs 49990..50010
2105+ // rhs has values 50000-50009 that are not in lhs
2106+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2107+ let rhs = HybridBitmap :: from_iter ( 49990u64 ..50010 ) ;
2108+ let mut lhs_buf = Vec :: new ( ) ;
2109+ let mut rhs_buf = Vec :: new ( ) ;
2110+ lhs. 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+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2117+
2118+ // Mixed (HybridSmall lhs, HybridLarge rhs): already rejected by len fast path
2119+ let lhs = HybridBitmap :: from_iter ( 0u64 ..31 ) ;
2120+ let rhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2121+ let mut lhs_buf = Vec :: new ( ) ;
2122+ let mut rhs_buf = Vec :: new ( ) ;
2123+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2124+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2125+ assert_eq ! (
2126+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2127+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2128+ ) ;
2129+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2130+
2131+ // Empty rhs: always true
2132+ let lhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2133+ let mut lhs_buf = Vec :: new ( ) ;
2134+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2135+ assert ! ( bitmap_has_all( & lhs_buf, & [ ] ) . unwrap( ) ) ;
2136+
2137+ // Empty lhs with non-empty rhs: always false
2138+ let rhs = HybridBitmap :: from_iter ( 0u64 ..50000 ) ;
2139+ let mut rhs_buf = Vec :: new ( ) ;
2140+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2141+ assert ! ( !bitmap_has_all( & [ ] , & rhs_buf) . unwrap( ) ) ;
2142+
2143+ // Both empty: true
2144+ assert ! ( bitmap_has_all( & [ ] , & [ ] ) . unwrap( ) ) ;
2145+
2146+ // Mixed (Legacy lhs, HybridLarge rhs)
2147+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2148+ for v in 0u64 ..50000 {
2149+ lhs_tree. insert ( v) ;
2150+ }
2151+ let rhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
2152+ let mut lhs_buf = Vec :: new ( ) ;
2153+ let mut rhs_buf = Vec :: new ( ) ;
2154+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2155+ rhs. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2156+ assert_eq ! (
2157+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2158+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2159+ ) ;
2160+
2161+ // Mixed (HybridLarge lhs, Legacy rhs)
2162+ let lhs = HybridBitmap :: from_iter ( 0u64 ..10000 ) ;
2163+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2164+ for v in 0u64 ..50000 {
2165+ rhs_tree. insert ( v) ;
2166+ }
2167+
2168+ let mut lhs_buf = Vec :: new ( ) ;
2169+ let mut rhs_buf = Vec :: new ( ) ;
2170+ lhs. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2171+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2172+ assert_eq ! (
2173+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2174+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2175+ ) ;
2176+
2177+ // Both Legacy
2178+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2179+ for v in 0u64 ..100 {
2180+ lhs_tree. insert ( v) ;
2181+ }
2182+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2183+ for v in 50u64 ..80 {
2184+ rhs_tree. insert ( v) ;
2185+ }
2186+ let mut lhs_buf = Vec :: new ( ) ;
2187+ let mut rhs_buf = Vec :: new ( ) ;
2188+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2189+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2190+ assert_eq ! (
2191+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2192+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2193+ ) ;
2194+ assert ! ( bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2195+
2196+ // Both Legacy, rhs not subset
2197+ let mut lhs_tree = RoaringTreemap :: new ( ) ;
2198+ for v in 0u64 ..100 {
2199+ lhs_tree. insert ( v) ;
2200+ }
2201+ let mut rhs_tree = RoaringTreemap :: new ( ) ;
2202+ for v in 50u64 ..150 {
2203+ rhs_tree. insert ( v) ;
2204+ }
2205+ let mut lhs_buf = Vec :: new ( ) ;
2206+ let mut rhs_buf = Vec :: new ( ) ;
2207+ lhs_tree. serialize_into ( & mut lhs_buf) . unwrap ( ) ;
2208+ rhs_tree. serialize_into ( & mut rhs_buf) . unwrap ( ) ;
2209+ assert_eq ! (
2210+ bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ,
2211+ ground_truth_has_all( & lhs_buf, & rhs_buf)
2212+ ) ;
2213+ assert ! ( !bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ) ;
2214+ }
19392215}
0 commit comments