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  }