github.com/coyove/sdss@v0.0.0-20231129015646-c2ec58cca6a2/contrib/roaring/roaringarray.go (about) 1 package roaring 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 9 "github.com/coyove/sdss/contrib/roaring/internal" 10 ) 11 12 type container interface { 13 // addOffset returns the (low, high) parts of the shifted container. 14 // Whenever one of them would be empty, nil will be returned instead to 15 // avoid unnecessary allocations. 16 addOffset(uint16) (container, container) 17 18 clone() container 19 and(container) container 20 andCardinality(container) int 21 iand(container) container // i stands for inplace 22 andNot(container) container 23 iandNot(container) container // i stands for inplace 24 isEmpty() bool 25 getCardinality() int 26 // rank returns the number of integers that are 27 // smaller or equal to x. rank(infinity) would be getCardinality(). 28 rank(uint16) int 29 30 iadd(x uint16) bool // inplace, returns true if x was new. 31 iaddReturnMinimized(uint16) container // may change return type to minimize storage. 32 33 //addRange(start, final int) container // range is [firstOfRange,lastOfRange) (unused) 34 iaddRange(start, endx int) container // i stands for inplace, range is [firstOfRange,endx) 35 36 iremove(x uint16) bool // inplace, returns true if x was present. 37 iremoveReturnMinimized(uint16) container // may change return type to minimize storage. 38 39 not(start, final int) container // range is [firstOfRange,lastOfRange) 40 inot(firstOfRange, endx int) container // i stands for inplace, range is [firstOfRange,endx) 41 xor(r container) container 42 getShortIterator() shortPeekable 43 iterate(cb func(x uint16) bool) bool 44 getReverseIterator() shortIterable 45 getManyIterator() manyIterable 46 contains(i uint16) bool 47 maximum() uint16 48 minimum() uint16 49 50 // equals is now logical equals; it does not require the 51 // same underlying container types, but compares across 52 // any of the implementations. 53 equals(r container) bool 54 55 fillLeastSignificant16bits(array []uint32, i int, mask uint32) int 56 or(r container) container 57 orCardinality(r container) int 58 isFull() bool 59 ior(r container) container // i stands for inplace 60 intersects(r container) bool // whether the two containers intersect 61 lazyOR(r container) container 62 lazyIOR(r container) container 63 getSizeInBytes() int 64 //removeRange(start, final int) container // range is [firstOfRange,lastOfRange) (unused) 65 iremoveRange(start, final int) container // i stands for inplace, range is [firstOfRange,lastOfRange) 66 selectInt(x uint16) int // selectInt returns the xth integer in the container 67 serializedSizeInBytes() int 68 writeTo(io.Writer) (int, error) 69 70 numberOfRuns() int 71 toEfficientContainer() container 72 String() string 73 containerType() contype 74 } 75 76 type contype uint8 77 78 const ( 79 bitmapContype contype = iota 80 arrayContype 81 run16Contype 82 run32Contype 83 ) 84 85 // careful: range is [firstOfRange,lastOfRange] 86 func rangeOfOnes(start, last int) container { 87 if start > MaxUint16 { 88 panic("rangeOfOnes called with start > MaxUint16") 89 } 90 if last > MaxUint16 { 91 panic("rangeOfOnes called with last > MaxUint16") 92 } 93 if start < 0 { 94 panic("rangeOfOnes called with start < 0") 95 } 96 if last < 0 { 97 panic("rangeOfOnes called with last < 0") 98 } 99 return newRunContainer16Range(uint16(start), uint16(last)) 100 } 101 102 type roaringArray struct { 103 keys []uint16 104 containers []container `msg:"-"` // don't try to serialize directly. 105 needCopyOnWrite []bool 106 copyOnWrite bool 107 } 108 109 func newRoaringArray() *roaringArray { 110 return &roaringArray{} 111 } 112 113 // runOptimize compresses the element containers to minimize space consumed. 114 // Q: how does this interact with copyOnWrite and needCopyOnWrite? 115 // A: since we aren't changing the logical content, just the representation, 116 // we don't bother to check the needCopyOnWrite bits. We replace 117 // (possibly all) elements of ra.containers in-place with space 118 // optimized versions. 119 func (ra *roaringArray) runOptimize() { 120 for i := range ra.containers { 121 ra.containers[i] = ra.containers[i].toEfficientContainer() 122 } 123 } 124 125 func (ra *roaringArray) appendContainer(key uint16, value container, mustCopyOnWrite bool) { 126 ra.keys = append(ra.keys, key) 127 ra.containers = append(ra.containers, value) 128 ra.needCopyOnWrite = append(ra.needCopyOnWrite, mustCopyOnWrite) 129 } 130 131 func (ra *roaringArray) appendWithoutCopy(sa roaringArray, startingindex int) { 132 mustCopyOnWrite := sa.needCopyOnWrite[startingindex] 133 ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex], mustCopyOnWrite) 134 } 135 136 func (ra *roaringArray) appendCopy(sa roaringArray, startingindex int) { 137 // cow only if the two request it, or if we already have a lightweight copy 138 copyonwrite := (ra.copyOnWrite && sa.copyOnWrite) || sa.needsCopyOnWrite(startingindex) 139 if !copyonwrite { 140 // since there is no copy-on-write, we need to clone the container (this is important) 141 ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex].clone(), copyonwrite) 142 } else { 143 ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex], copyonwrite) 144 if !sa.needsCopyOnWrite(startingindex) { 145 sa.setNeedsCopyOnWrite(startingindex) 146 } 147 } 148 } 149 150 func (ra *roaringArray) appendWithoutCopyMany(sa roaringArray, startingindex, end int) { 151 for i := startingindex; i < end; i++ { 152 ra.appendWithoutCopy(sa, i) 153 } 154 } 155 156 func (ra *roaringArray) appendCopyMany(sa roaringArray, startingindex, end int) { 157 for i := startingindex; i < end; i++ { 158 ra.appendCopy(sa, i) 159 } 160 } 161 162 func (ra *roaringArray) appendCopiesUntil(sa roaringArray, stoppingKey uint16) { 163 // cow only if the two request it, or if we already have a lightweight copy 164 copyonwrite := ra.copyOnWrite && sa.copyOnWrite 165 166 for i := 0; i < sa.size(); i++ { 167 if sa.keys[i] >= stoppingKey { 168 break 169 } 170 thiscopyonewrite := copyonwrite || sa.needsCopyOnWrite(i) 171 if thiscopyonewrite { 172 ra.appendContainer(sa.keys[i], sa.containers[i], thiscopyonewrite) 173 if !sa.needsCopyOnWrite(i) { 174 sa.setNeedsCopyOnWrite(i) 175 } 176 177 } else { 178 // since there is no copy-on-write, we need to clone the container (this is important) 179 ra.appendContainer(sa.keys[i], sa.containers[i].clone(), thiscopyonewrite) 180 181 } 182 } 183 } 184 185 func (ra *roaringArray) appendCopiesAfter(sa roaringArray, beforeStart uint16) { 186 // cow only if the two request it, or if we already have a lightweight copy 187 copyonwrite := ra.copyOnWrite && sa.copyOnWrite 188 189 startLocation := sa.getIndex(beforeStart) 190 if startLocation >= 0 { 191 startLocation++ 192 } else { 193 startLocation = -startLocation - 1 194 } 195 196 for i := startLocation; i < sa.size(); i++ { 197 thiscopyonewrite := copyonwrite || sa.needsCopyOnWrite(i) 198 if thiscopyonewrite { 199 ra.appendContainer(sa.keys[i], sa.containers[i], thiscopyonewrite) 200 if !sa.needsCopyOnWrite(i) { 201 sa.setNeedsCopyOnWrite(i) 202 } 203 } else { 204 // since there is no copy-on-write, we need to clone the container (this is important) 205 ra.appendContainer(sa.keys[i], sa.containers[i].clone(), thiscopyonewrite) 206 207 } 208 } 209 } 210 211 func (ra *roaringArray) removeIndexRange(begin, end int) { 212 if end <= begin { 213 return 214 } 215 216 r := end - begin 217 218 copy(ra.keys[begin:], ra.keys[end:]) 219 copy(ra.containers[begin:], ra.containers[end:]) 220 copy(ra.needCopyOnWrite[begin:], ra.needCopyOnWrite[end:]) 221 222 ra.resize(len(ra.keys) - r) 223 } 224 225 func (ra *roaringArray) resize(newsize int) { 226 for k := newsize; k < len(ra.containers); k++ { 227 ra.containers[k] = nil 228 } 229 230 ra.keys = ra.keys[:newsize] 231 ra.containers = ra.containers[:newsize] 232 ra.needCopyOnWrite = ra.needCopyOnWrite[:newsize] 233 } 234 235 func (ra *roaringArray) clear() { 236 ra.resize(0) 237 ra.copyOnWrite = false 238 } 239 240 func (ra *roaringArray) clone() *roaringArray { 241 242 sa := roaringArray{} 243 sa.copyOnWrite = ra.copyOnWrite 244 245 // this is where copyOnWrite is used. 246 if ra.copyOnWrite { 247 sa.keys = make([]uint16, len(ra.keys)) 248 copy(sa.keys, ra.keys) 249 sa.containers = make([]container, len(ra.containers)) 250 copy(sa.containers, ra.containers) 251 sa.needCopyOnWrite = make([]bool, len(ra.needCopyOnWrite)) 252 253 ra.markAllAsNeedingCopyOnWrite() 254 sa.markAllAsNeedingCopyOnWrite() 255 256 // sa.needCopyOnWrite is shared 257 } else { 258 // make a full copy 259 260 sa.keys = make([]uint16, len(ra.keys)) 261 copy(sa.keys, ra.keys) 262 263 sa.containers = make([]container, len(ra.containers)) 264 for i := range sa.containers { 265 sa.containers[i] = ra.containers[i].clone() 266 } 267 268 sa.needCopyOnWrite = make([]bool, len(ra.needCopyOnWrite)) 269 } 270 return &sa 271 } 272 273 // clone all containers which have needCopyOnWrite set to true 274 // This can be used to make sure it is safe to munmap a []byte 275 // that the roaring array may still have a reference to. 276 func (ra *roaringArray) cloneCopyOnWriteContainers() { 277 for i, needCopyOnWrite := range ra.needCopyOnWrite { 278 if needCopyOnWrite { 279 ra.containers[i] = ra.containers[i].clone() 280 ra.needCopyOnWrite[i] = false 281 } 282 } 283 } 284 285 // unused function: 286 //func (ra *roaringArray) containsKey(x uint16) bool { 287 // return (ra.binarySearch(0, int64(len(ra.keys)), x) >= 0) 288 //} 289 290 func (ra *roaringArray) getContainer(x uint16) container { 291 i := ra.binarySearch(0, int64(len(ra.keys)), x) 292 if i < 0 { 293 return nil 294 } 295 return ra.containers[i] 296 } 297 298 func (ra *roaringArray) getContainerAtIndex(i int) container { 299 return ra.containers[i] 300 } 301 302 func (ra *roaringArray) getFastContainerAtIndex(i int, needsWriteable bool) container { 303 c := ra.getContainerAtIndex(i) 304 switch t := c.(type) { 305 case *arrayContainer: 306 c = t.toBitmapContainer() 307 case *runContainer16: 308 if !t.isFull() { 309 c = t.toBitmapContainer() 310 } 311 case *bitmapContainer: 312 if needsWriteable && ra.needCopyOnWrite[i] { 313 c = ra.containers[i].clone() 314 } 315 } 316 return c 317 } 318 319 // getUnionedWritableContainer switches behavior for in-place Or 320 // depending on whether the container requires a copy on write. 321 // If it does using the non-inplace or() method leads to fewer allocations. 322 func (ra *roaringArray) getUnionedWritableContainer(pos int, other container) container { 323 if ra.needCopyOnWrite[pos] { 324 return ra.getContainerAtIndex(pos).or(other) 325 } 326 return ra.getContainerAtIndex(pos).ior(other) 327 328 } 329 330 func (ra *roaringArray) getWritableContainerAtIndex(i int) container { 331 if ra.needCopyOnWrite[i] { 332 ra.containers[i] = ra.containers[i].clone() 333 ra.needCopyOnWrite[i] = false 334 } 335 return ra.containers[i] 336 } 337 338 func (ra *roaringArray) getIndex(x uint16) int { 339 // before the binary search, we optimize for frequent cases 340 size := len(ra.keys) 341 if (size == 0) || (ra.keys[size-1] == x) { 342 return size - 1 343 } 344 return ra.binarySearch(0, int64(size), x) 345 } 346 347 func (ra *roaringArray) getKeyAtIndex(i int) uint16 { 348 return ra.keys[i] 349 } 350 351 func (ra *roaringArray) insertNewKeyValueAt(i int, key uint16, value container) { 352 ra.keys = append(ra.keys, 0) 353 ra.containers = append(ra.containers, nil) 354 355 copy(ra.keys[i+1:], ra.keys[i:]) 356 copy(ra.containers[i+1:], ra.containers[i:]) 357 358 ra.keys[i] = key 359 ra.containers[i] = value 360 361 ra.needCopyOnWrite = append(ra.needCopyOnWrite, false) 362 copy(ra.needCopyOnWrite[i+1:], ra.needCopyOnWrite[i:]) 363 ra.needCopyOnWrite[i] = false 364 } 365 366 func (ra *roaringArray) remove(key uint16) bool { 367 i := ra.binarySearch(0, int64(len(ra.keys)), key) 368 if i >= 0 { // if a new key 369 ra.removeAtIndex(i) 370 return true 371 } 372 return false 373 } 374 375 func (ra *roaringArray) removeAtIndex(i int) { 376 copy(ra.keys[i:], ra.keys[i+1:]) 377 copy(ra.containers[i:], ra.containers[i+1:]) 378 379 copy(ra.needCopyOnWrite[i:], ra.needCopyOnWrite[i+1:]) 380 381 ra.resize(len(ra.keys) - 1) 382 } 383 384 func (ra *roaringArray) setContainerAtIndex(i int, c container) { 385 ra.containers[i] = c 386 } 387 388 func (ra *roaringArray) replaceKeyAndContainerAtIndex(i int, key uint16, c container, mustCopyOnWrite bool) { 389 ra.keys[i] = key 390 ra.containers[i] = c 391 ra.needCopyOnWrite[i] = mustCopyOnWrite 392 } 393 394 func (ra *roaringArray) size() int { 395 return len(ra.keys) 396 } 397 398 func (ra *roaringArray) binarySearch(begin, end int64, ikey uint16) int { 399 low := begin 400 high := end - 1 401 for low+16 <= high { 402 middleIndex := low + (high-low)/2 // avoid overflow 403 middleValue := ra.keys[middleIndex] 404 405 if middleValue < ikey { 406 low = middleIndex + 1 407 } else if middleValue > ikey { 408 high = middleIndex - 1 409 } else { 410 return int(middleIndex) 411 } 412 } 413 for ; low <= high; low++ { 414 val := ra.keys[low] 415 if val >= ikey { 416 if val == ikey { 417 return int(low) 418 } 419 break 420 } 421 } 422 return -int(low + 1) 423 } 424 425 func (ra *roaringArray) equals(o interface{}) bool { 426 srb, ok := o.(roaringArray) 427 if ok { 428 429 if srb.size() != ra.size() { 430 return false 431 } 432 for i, k := range ra.keys { 433 if k != srb.keys[i] { 434 return false 435 } 436 } 437 438 for i, c := range ra.containers { 439 if !c.equals(srb.containers[i]) { 440 return false 441 } 442 } 443 return true 444 } 445 return false 446 } 447 448 func (ra *roaringArray) headerSize() uint64 { 449 size := uint64(len(ra.keys)) 450 if ra.hasRunCompression() { 451 if size < noOffsetThreshold { // for small bitmaps, we omit the offsets 452 return 4 + (size+7)/8 + 4*size 453 } 454 return 4 + (size+7)/8 + 8*size // - 4 because we pack the size with the cookie 455 } 456 return 4 + 4 + 8*size 457 458 } 459 460 // should be dirt cheap 461 func (ra *roaringArray) serializedSizeInBytes() uint64 { 462 answer := ra.headerSize() 463 for _, c := range ra.containers { 464 answer += uint64(c.serializedSizeInBytes()) 465 } 466 return answer 467 } 468 469 // 470 // spec: https://github.com/RoaringBitmap/RoaringFormatSpec 471 // 472 func (ra *roaringArray) writeTo(w io.Writer) (n int64, err error) { 473 hasRun := ra.hasRunCompression() 474 isRunSizeInBytes := 0 475 cookieSize := 8 476 if hasRun { 477 cookieSize = 4 478 isRunSizeInBytes = (len(ra.keys) + 7) / 8 479 } 480 descriptiveHeaderSize := 4 * len(ra.keys) 481 preambleSize := cookieSize + isRunSizeInBytes + descriptiveHeaderSize 482 483 buf := make([]byte, preambleSize+4*len(ra.keys)) 484 485 nw := 0 486 487 if hasRun { 488 binary.LittleEndian.PutUint16(buf[0:], uint16(serialCookie)) 489 nw += 2 490 binary.LittleEndian.PutUint16(buf[2:], uint16(len(ra.keys)-1)) 491 nw += 2 492 // compute isRun bitmap without temporary allocation 493 var runbitmapslice = buf[nw : nw+isRunSizeInBytes] 494 for i, c := range ra.containers { 495 switch c.(type) { 496 case *runContainer16: 497 runbitmapslice[i/8] |= 1 << (uint(i) % 8) 498 } 499 } 500 nw += isRunSizeInBytes 501 } else { 502 binary.LittleEndian.PutUint32(buf[0:], uint32(serialCookieNoRunContainer)) 503 nw += 4 504 binary.LittleEndian.PutUint32(buf[4:], uint32(len(ra.keys))) 505 nw += 4 506 } 507 508 // descriptive header 509 for i, key := range ra.keys { 510 binary.LittleEndian.PutUint16(buf[nw:], key) 511 nw += 2 512 c := ra.containers[i] 513 binary.LittleEndian.PutUint16(buf[nw:], uint16(c.getCardinality()-1)) 514 nw += 2 515 } 516 517 startOffset := int64(preambleSize + 4*len(ra.keys)) 518 if !hasRun || (len(ra.keys) >= noOffsetThreshold) { 519 // offset header 520 for _, c := range ra.containers { 521 binary.LittleEndian.PutUint32(buf[nw:], uint32(startOffset)) 522 nw += 4 523 switch rc := c.(type) { 524 case *runContainer16: 525 startOffset += 2 + int64(len(rc.iv))*4 526 default: 527 startOffset += int64(getSizeInBytesFromCardinality(c.getCardinality())) 528 } 529 } 530 } 531 532 written, err := w.Write(buf[:nw]) 533 if err != nil { 534 return n, err 535 } 536 n += int64(written) 537 538 for _, c := range ra.containers { 539 written, err := c.writeTo(w) 540 if err != nil { 541 return n, err 542 } 543 n += int64(written) 544 } 545 return n, nil 546 } 547 548 // 549 // spec: https://github.com/RoaringBitmap/RoaringFormatSpec 550 // 551 func (ra *roaringArray) toBytes() ([]byte, error) { 552 var buf bytes.Buffer 553 _, err := ra.writeTo(&buf) 554 return buf.Bytes(), err 555 } 556 557 func (ra *roaringArray) readFrom(stream internal.ByteInput, cookieHeader ...byte) (int64, error) { 558 var cookie uint32 559 var err error 560 if len(cookieHeader) > 0 && len(cookieHeader) != 4 { 561 return int64(len(cookieHeader)), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: incorrect size of cookie header") 562 } 563 if len(cookieHeader) == 4 { 564 cookie = binary.LittleEndian.Uint32(cookieHeader) 565 } else { 566 cookie, err = stream.ReadUInt32() 567 if err != nil { 568 return stream.GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: %s", err) 569 } 570 } 571 572 var size uint32 573 var isRunBitmap []byte 574 575 if cookie&0x0000FFFF == serialCookie { 576 size = uint32(cookie>>16 + 1) 577 // create is-run-container bitmap 578 isRunBitmapSize := (int(size) + 7) / 8 579 isRunBitmap, err = stream.Next(isRunBitmapSize) 580 581 if err != nil { 582 return stream.GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read is-run bitmap, got: %s", err) 583 } 584 } else if cookie == serialCookieNoRunContainer { 585 size, err = stream.ReadUInt32() 586 if err != nil { 587 return stream.GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read a bitmap size: %s", err) 588 } 589 } else { 590 return stream.GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: did not find expected serialCookie in header") 591 } 592 593 if size > (1 << 16) { 594 return stream.GetReadBytes(), fmt.Errorf("it is logically impossible to have more than (1<<16) containers") 595 } 596 597 // descriptive header 598 buf, err := stream.Next(2 * 2 * int(size)) 599 600 if err != nil { 601 return stream.GetReadBytes(), fmt.Errorf("failed to read descriptive header: %s", err) 602 } 603 604 keycard := byteSliceAsUint16Slice(buf) 605 606 if isRunBitmap == nil || size >= noOffsetThreshold { 607 if err := stream.SkipBytes(int(size) * 4); err != nil { 608 return stream.GetReadBytes(), fmt.Errorf("failed to skip bytes: %s", err) 609 } 610 } 611 612 // Allocate slices upfront as number of containers is known 613 if cap(ra.containers) >= int(size) { 614 ra.containers = ra.containers[:size] 615 } else { 616 ra.containers = make([]container, size) 617 } 618 619 if cap(ra.keys) >= int(size) { 620 ra.keys = ra.keys[:size] 621 } else { 622 ra.keys = make([]uint16, size) 623 } 624 625 if cap(ra.needCopyOnWrite) >= int(size) { 626 ra.needCopyOnWrite = ra.needCopyOnWrite[:size] 627 } else { 628 ra.needCopyOnWrite = make([]bool, size) 629 } 630 631 for i := uint32(0); i < size; i++ { 632 key := keycard[2*i] 633 card := int(keycard[2*i+1]) + 1 634 ra.keys[i] = key 635 ra.needCopyOnWrite[i] = true 636 637 if isRunBitmap != nil && isRunBitmap[i/8]&(1<<(i%8)) != 0 { 638 // run container 639 nr, err := stream.ReadUInt16() 640 641 if err != nil { 642 return 0, fmt.Errorf("failed to read runtime container size: %s", err) 643 } 644 645 buf, err := stream.Next(int(nr) * 4) 646 647 if err != nil { 648 return stream.GetReadBytes(), fmt.Errorf("failed to read runtime container content: %s", err) 649 } 650 651 nb := runContainer16{ 652 iv: byteSliceAsInterval16Slice(buf), 653 } 654 655 ra.containers[i] = &nb 656 } else if card > arrayDefaultMaxSize { 657 // bitmap container 658 buf, err := stream.Next(arrayDefaultMaxSize * 2) 659 660 if err != nil { 661 return stream.GetReadBytes(), fmt.Errorf("failed to read bitmap container: %s", err) 662 } 663 664 nb := bitmapContainer{ 665 cardinality: card, 666 bitmap: byteSliceAsUint64Slice(buf), 667 } 668 669 ra.containers[i] = &nb 670 } else { 671 // array container 672 buf, err := stream.Next(card * 2) 673 674 if err != nil { 675 return stream.GetReadBytes(), fmt.Errorf("failed to read array container: %s", err) 676 } 677 678 nb := arrayContainer{ 679 byteSliceAsUint16Slice(buf), 680 } 681 682 ra.containers[i] = &nb 683 } 684 } 685 686 return stream.GetReadBytes(), nil 687 } 688 689 func (ra *roaringArray) hasRunCompression() bool { 690 for _, c := range ra.containers { 691 switch c.(type) { 692 case *runContainer16: 693 return true 694 } 695 } 696 return false 697 } 698 699 func (ra *roaringArray) advanceUntil(min uint16, pos int) int { 700 lower := pos + 1 701 702 if lower >= len(ra.keys) || ra.keys[lower] >= min { 703 return lower 704 } 705 706 spansize := 1 707 708 for lower+spansize < len(ra.keys) && ra.keys[lower+spansize] < min { 709 spansize *= 2 710 } 711 var upper int 712 if lower+spansize < len(ra.keys) { 713 upper = lower + spansize 714 } else { 715 upper = len(ra.keys) - 1 716 } 717 718 if ra.keys[upper] == min { 719 return upper 720 } 721 722 if ra.keys[upper] < min { 723 // means 724 // array 725 // has no 726 // item 727 // >= min 728 // pos = array.length; 729 return len(ra.keys) 730 } 731 732 // we know that the next-smallest span was too small 733 lower += (spansize >> 1) 734 735 mid := 0 736 for lower+1 != upper { 737 mid = (lower + upper) >> 1 738 if ra.keys[mid] == min { 739 return mid 740 } else if ra.keys[mid] < min { 741 lower = mid 742 } else { 743 upper = mid 744 } 745 } 746 return upper 747 } 748 749 func (ra *roaringArray) markAllAsNeedingCopyOnWrite() { 750 for i := range ra.needCopyOnWrite { 751 ra.needCopyOnWrite[i] = true 752 } 753 } 754 755 func (ra *roaringArray) needsCopyOnWrite(i int) bool { 756 return ra.needCopyOnWrite[i] 757 } 758 759 func (ra *roaringArray) setNeedsCopyOnWrite(i int) { 760 ra.needCopyOnWrite[i] = true 761 }