CardinalityInRange returns the number of integers that are in the half-open range [start, end). It is equivalent to Rank(uint32(end-1)) - Rank(uint32(start-1)) for start > 0, but is optimized to only scan containers that overlap the range, making it O(k) in the number of containers spanned by [start
(start, end uint64)
| 1279 | // in total containers. The parameter type is uint64 to allow end = 1<<32 |
| 1280 | // (the full 32-bit range). |
| 1281 | func (rb *Bitmap) CardinalityInRange(start, end uint64) uint64 { |
| 1282 | if start >= end { |
| 1283 | return 0 |
| 1284 | } |
| 1285 | if end > MaxUint32+1 { |
| 1286 | end = MaxUint32 + 1 |
| 1287 | } |
| 1288 | |
| 1289 | hbStart := highbits(uint32(start)) |
| 1290 | hbEnd := highbits(uint32(end - 1)) // end-1 is the last included value |
| 1291 | |
| 1292 | size := rb.highlowcontainer.size() |
| 1293 | |
| 1294 | // Binary-search to find the first container index >= hbStart. |
| 1295 | startIdx := rb.highlowcontainer.getIndex(hbStart) |
| 1296 | if startIdx < 0 { |
| 1297 | startIdx = -startIdx - 1 // insertion point |
| 1298 | } |
| 1299 | if startIdx >= size { |
| 1300 | return 0 |
| 1301 | } |
| 1302 | |
| 1303 | result := uint64(0) |
| 1304 | |
| 1305 | // Handle the case where start and end are in the same container. |
| 1306 | if hbStart == hbEnd { |
| 1307 | key := rb.highlowcontainer.getKeyAtIndex(startIdx) |
| 1308 | if key == hbStart { |
| 1309 | lo := uint(lowbits(uint32(start))) |
| 1310 | hi := uint(lowbits(uint32(end-1))) + 1 |
| 1311 | return uint64(rb.highlowcontainer.getContainerAtIndex(startIdx).getCardinalityInRange(lo, hi)) |
| 1312 | } |
| 1313 | return 0 |
| 1314 | } |
| 1315 | |
| 1316 | // Handle the first container (may be partial). |
| 1317 | key := rb.highlowcontainer.getKeyAtIndex(startIdx) |
| 1318 | if key == hbStart { |
| 1319 | lo := uint(lowbits(uint32(start))) |
| 1320 | result += uint64(rb.highlowcontainer.getContainerAtIndex(startIdx).getCardinalityInRange(lo, 1<<16)) |
| 1321 | startIdx++ |
| 1322 | } |
| 1323 | |
| 1324 | // Binary-search to find the last container index <= hbEnd. |
| 1325 | endIdx := rb.highlowcontainer.getIndex(hbEnd) |
| 1326 | endPresent := endIdx >= 0 |
| 1327 | if endIdx < 0 { |
| 1328 | endIdx = -endIdx - 2 // index of the last container with key < hbEnd |
| 1329 | } |
| 1330 | |
| 1331 | // Tight loop over middle containers — no per-iteration key comparisons. |
| 1332 | for i := startIdx; i <= endIdx; i++ { |
| 1333 | if endPresent && i == endIdx { |
| 1334 | break // this is the end container, handled below |
| 1335 | } |
| 1336 | result += uint64(rb.highlowcontainer.getContainerAtIndex(i).getCardinality()) |
| 1337 | } |
| 1338 |