github.com/outcaste-io/sroar@v0.0.0-20221229172112-1fb64f14314c/container.go (about)

     1  /*
     2   * Copyright 2021 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package sroar
    18  
    19  import (
    20  	"encoding/hex"
    21  	"fmt"
    22  	"math"
    23  	"math/bits"
    24  	"os"
    25  	"strings"
    26  )
    27  
    28  // container uses extra 4 []uint16 in the front as header.
    29  // container[0] is used for storing the size of the container, expressed in Uint16.
    30  // The container size cannot exceed the vicinity of 8KB. At 8KB, we switch from packed arrays to
    31  // bitmaps. We can fit the entire uint16 worth of bitmaps in 8KB (2^16 / 8 = 8
    32  // KB).
    33  
    34  const (
    35  	typeArray  uint16 = 0x00
    36  	typeBitmap uint16 = 0x01
    37  
    38  	// Container header.
    39  	indexSize        int = 0
    40  	indexType        int = 1
    41  	indexCardinality int = 2
    42  	// Index 2 and 3 is used for cardinality. We need 2 uint16s to store cardinality because
    43  	// 2^16 will not fit in uint16.
    44  	startIdx uint16 = 4
    45  
    46  	minContainerSize = 64 // In Uint16.
    47  	// Bitmap container can contain 2^16 integers. Each integer would use one bit to represent.
    48  	// Given that our data is represented in []uint16s, that'd mean the size of container to store
    49  	// it would be divided by 16.
    50  	// 4 for header and 4096 for storing bitmap container. In Uint16.
    51  	maxContainerSize = 4 + (1<<16)/16
    52  )
    53  
    54  func dataAt(data []uint16, i int) uint16 { return data[int(startIdx)+i] }
    55  
    56  func incrCardinality(data []uint16) {
    57  	cur := getCardinality(data)
    58  	if cur+1 > math.MaxUint16 {
    59  		data[indexCardinality+1] = 1
    60  	} else {
    61  		data[indexCardinality]++
    62  	}
    63  }
    64  
    65  var invalidCardinality int = math.MaxUint16 + 10
    66  var maxCardinality int = math.MaxUint16 + 1
    67  
    68  func getCardinality(data []uint16) int {
    69  	// This sum has to be done using two ints to avoid overflow.
    70  	return int(data[indexCardinality]) + int(data[indexCardinality+1])
    71  }
    72  
    73  func setCardinality(data []uint16, c int) {
    74  	if c > math.MaxUint16 {
    75  		data[indexCardinality] = math.MaxUint16
    76  		data[indexCardinality+1] = uint16(c - math.MaxUint16)
    77  	} else {
    78  		data[indexCardinality] = uint16(c)
    79  		data[indexCardinality+1] = 0
    80  	}
    81  }
    82  
    83  func zeroOutContainer(c []uint16) {
    84  	switch c[indexType] {
    85  	case typeArray:
    86  		array(c).zeroOut()
    87  	case typeBitmap:
    88  		bitmap(c).zeroOut()
    89  	}
    90  }
    91  
    92  func removeRangeContainer(c []uint16, lo, hi uint16) {
    93  	switch c[indexType] {
    94  	case typeArray:
    95  		array(c).removeRange(lo, hi)
    96  	case typeBitmap:
    97  		bitmap(c).removeRange(lo, hi)
    98  	}
    99  }
   100  
   101  func calculateAndSetCardinality(data []uint16) {
   102  	if data[indexType] != typeBitmap {
   103  		panic("Non-bitmap containers should always have cardinality set correctly")
   104  	}
   105  	b := bitmap(data)
   106  	card := b.cardinality()
   107  	setCardinality(b, card)
   108  }
   109  
   110  type array []uint16
   111  
   112  // find returns the index of the first element >= x.
   113  // The index is based on data portion of the container, ignoring startIdx.
   114  // If the element > than all elements present, then N is returned where N = cardinality of the
   115  // container.
   116  func (c array) find(x uint16) int {
   117  	N := getCardinality(c)
   118  	for i := int(startIdx); i < int(startIdx)+N; i++ {
   119  		if len(c) <= int(i) {
   120  			panic(fmt.Sprintf("find: %d len(c) %d <= i %d\n", x, len(c), i))
   121  		}
   122  		if c[i] >= x {
   123  			return int(i - int(startIdx))
   124  		}
   125  	}
   126  	return N
   127  }
   128  
   129  func (c array) rank(x uint16) int {
   130  	N := getCardinality(c)
   131  	idx := c.find(x)
   132  	if idx == N {
   133  		return -1
   134  	}
   135  	return idx
   136  }
   137  
   138  func (c array) has(x uint16) bool {
   139  	N := getCardinality(c)
   140  	idx := c.find(x)
   141  	if idx == N {
   142  		return false
   143  	}
   144  	return c[int(startIdx)+idx] == x
   145  }
   146  
   147  func (c array) add(x uint16) bool {
   148  	idx := c.find(x)
   149  	N := getCardinality(c)
   150  	offset := int(startIdx) + idx
   151  
   152  	if int(idx) < N {
   153  		if c[offset] == x {
   154  			return false
   155  		}
   156  		// The entry at offset is the first entry, which is greater than x. Move it to the right.
   157  		copy(c[offset+1:], c[offset:])
   158  	}
   159  	if offset >= len(c) {
   160  		fmt.Printf("offset: %d len(c): %d idx: %d N: %d isFull: %v\n", offset, len(c), idx, N, c.isFull())
   161  		fmt.Printf("array:\n%s\n", hex.Dump(toByteSlice(c)))
   162  		for ei, ee := range c {
   163  			fmt.Printf("[%d] %d\n", ei, ee)
   164  		}
   165  		fmt.Printf("Trying to add x: %d\n", x)
   166  		os.Exit(1)
   167  	}
   168  	c[offset] = x
   169  	incrCardinality(c)
   170  	return true
   171  }
   172  
   173  func (c array) remove(x uint16) bool {
   174  	idx := c.find(x)
   175  	N := getCardinality(c)
   176  	offset := int(startIdx) + idx
   177  
   178  	if int(idx) < N {
   179  		if c[offset] != x {
   180  			return false
   181  		}
   182  		copy(c[offset:], c[offset+1:])
   183  		setCardinality(c, N-1)
   184  		return true
   185  	}
   186  	return false
   187  }
   188  
   189  func (c array) removeRange(lo, hi uint16) {
   190  	if hi < lo {
   191  		panic(fmt.Sprintf("args must satisfy lo <= hi, got lo: %d, hi: %d\n", lo, hi))
   192  	}
   193  	loIdx := c.find(lo)
   194  	hiIdx := c.find(hi)
   195  
   196  	st := int(startIdx)
   197  	loVal := c[st+loIdx]
   198  	N := getCardinality(c)
   199  
   200  	// remove range doesn't intersect with any element in the array.
   201  	if hi < loVal || loIdx == N {
   202  		return
   203  	}
   204  	if hiIdx == N {
   205  		if loIdx > 0 {
   206  			c = c[:int(startIdx)+loIdx-1]
   207  		} else {
   208  			c = c[:int(startIdx)]
   209  		}
   210  		setCardinality(c, loIdx)
   211  		return
   212  	}
   213  	if c[st+hiIdx] == hi {
   214  		hiIdx++
   215  	}
   216  	copy(c[st+loIdx:], c[st+hiIdx:])
   217  	setCardinality(c, N-hiIdx+loIdx)
   218  }
   219  
   220  func (c array) zeroOut() {
   221  	setCardinality(c, 0)
   222  }
   223  
   224  // TODO: Figure out how memory allocation would work in these situations. Perhaps use allocator here?
   225  func (c array) andArray(other array) []uint16 {
   226  	min := min(getCardinality(c), getCardinality(other))
   227  
   228  	setc := c.all()
   229  	seto := other.all()
   230  
   231  	out := make([]uint16, int(startIdx)+min+1)
   232  	num := uint16(intersection2by2(setc, seto, out[startIdx:]))
   233  
   234  	// Truncate out to how many values were found.
   235  	out = out[:startIdx+num+1]
   236  	out[indexType] = typeArray
   237  	out[indexSize] = uint16(len(out))
   238  	setCardinality(out, int(num))
   239  	return out
   240  }
   241  
   242  // TODO: We can do this operation in-place on the src array.
   243  func (c array) andNotArray(other array, buf []uint16) []uint16 {
   244  	max := getCardinality(c)
   245  	out := make([]uint16, int(startIdx)+max+1)
   246  
   247  	andRes := array(c.andArray(other)).all()
   248  	srcVals := array(c).all()
   249  	num := uint16(difference(srcVals, andRes, out[startIdx:]))
   250  
   251  	// Truncate out to how many values were found.
   252  	out = out[:startIdx+num+1]
   253  	out[indexType] = typeArray
   254  	out[indexSize] = uint16(len(out))
   255  	setCardinality(out, int(num))
   256  	return out
   257  }
   258  
   259  func (c array) orArray(other array, buf []uint16, runMode int) []uint16 {
   260  	// We ignore runInline for this call.
   261  
   262  	max := getCardinality(c) + getCardinality(other)
   263  	if max > 4096 {
   264  		// Use bitmap container.
   265  		out := bitmap(c.toBitmapContainer(buf))
   266  		// For now, just keep it as a bitmap. No need to change if the
   267  		// cardinality is smaller than 4096.
   268  		out.orArray(other, nil, runMode|runInline)
   269  		// Return out because out is pointing to buf. This would allow the
   270  		// receiver to copy out.
   271  		return out
   272  	}
   273  
   274  	// The output would be of typeArray.
   275  	out := buf[:int(startIdx)+max]
   276  	num := union2by2(c.all(), other.all(), out[startIdx:])
   277  	out[indexType] = typeArray
   278  	out[indexSize] = uint16(len(out))
   279  	setCardinality(out, num)
   280  	return out
   281  }
   282  
   283  var tmp = make([]uint16, 8192)
   284  
   285  func (c array) andBitmap(other bitmap) []uint16 {
   286  	out := make([]uint16, int(startIdx)+getCardinality(c)+2) // some extra space.
   287  	out[indexType] = typeArray
   288  
   289  	pos := startIdx
   290  	for _, x := range c.all() {
   291  		out[pos] = x
   292  		pos += other.bitValue(x)
   293  	}
   294  
   295  	// Ensure we have at least one empty slot at the end.
   296  	res := out[:pos+1]
   297  	res[indexSize] = uint16(len(res))
   298  	setCardinality(res, int(pos-startIdx))
   299  	return res
   300  }
   301  
   302  // TODO: Write an optmized version of this function.
   303  func (c array) andNotBitmap(other bitmap, buf []uint16) []uint16 {
   304  	assert(len(buf) == maxContainerSize)
   305  	res := array(buf)
   306  	Memclr(res)
   307  	res[indexSize] = 4
   308  	for _, e := range c.all() {
   309  		if !other.has(e) {
   310  			res.add(e)
   311  		}
   312  	}
   313  	return res
   314  }
   315  
   316  func (c array) isFull() bool {
   317  	N := getCardinality(c)
   318  	return int(startIdx)+N >= len(c)
   319  }
   320  
   321  func (c array) all() []uint16 {
   322  	N := getCardinality(c)
   323  	return c[startIdx : int(startIdx)+N]
   324  }
   325  
   326  func (c array) minimum() uint16 {
   327  	N := getCardinality(c)
   328  	if N == 0 {
   329  		return 0
   330  	}
   331  	return c[startIdx]
   332  }
   333  
   334  func (c array) maximum() uint16 {
   335  	N := getCardinality(c)
   336  	if N == 0 {
   337  		return 0
   338  	}
   339  	return c[int(startIdx)+N-1]
   340  }
   341  
   342  func (c array) toBitmapContainer(buf []uint16) []uint16 {
   343  	if len(buf) == 0 {
   344  		buf = make([]uint16, maxContainerSize)
   345  	} else {
   346  		assert(len(buf) == maxContainerSize)
   347  		assert(len(buf) == copy(buf, empty))
   348  	}
   349  
   350  	b := bitmap(buf)
   351  	b[indexSize] = maxContainerSize
   352  	b[indexType] = typeBitmap
   353  	setCardinality(b, getCardinality(c))
   354  
   355  	data := b[startIdx:]
   356  	for _, x := range c.all() {
   357  		idx := x >> 4
   358  		pos := x & 0xF
   359  		data[idx] |= bitmapMask[pos]
   360  	}
   361  	return b
   362  }
   363  
   364  func (c array) String() string {
   365  	var b strings.Builder
   366  	b.WriteString(fmt.Sprintf("Size: %d\n", c[0]))
   367  	for i, val := range c[startIdx:] {
   368  		b.WriteString(fmt.Sprintf("%d: %d\n", i, val))
   369  	}
   370  	return b.String()
   371  }
   372  
   373  type bitmap []uint16
   374  
   375  var bitmapMask []uint16
   376  
   377  func init() {
   378  	bitmapMask = make([]uint16, 16)
   379  	for i := 0; i < 16; i++ {
   380  		bitmapMask[i] = 1 << (15 - i)
   381  	}
   382  }
   383  
   384  func (b bitmap) add(x uint16) bool {
   385  	idx := x >> 4
   386  	pos := x & 0xF
   387  
   388  	if has := b[startIdx+idx] & bitmapMask[pos]; has > 0 {
   389  		return false
   390  	}
   391  
   392  	b[startIdx+idx] |= bitmapMask[pos]
   393  	incrCardinality(b)
   394  	return true
   395  }
   396  
   397  func (b bitmap) remove(x uint16) bool {
   398  	idx := x >> 4
   399  	pos := x & 0xF
   400  
   401  	c := getCardinality(b)
   402  	if has := b[startIdx+idx] & bitmapMask[pos]; has > 0 {
   403  		b[startIdx+idx] ^= bitmapMask[pos]
   404  		setCardinality(b, c-1)
   405  		return true
   406  	}
   407  	return false
   408  }
   409  
   410  func (b bitmap) removeRange(lo, hi uint16) {
   411  	loIdx := lo >> 4
   412  	loPos := lo & 0xF
   413  
   414  	hiIdx := hi >> 4
   415  	hiPos := hi & 0xF
   416  
   417  	N := getCardinality(b)
   418  	var removed int
   419  	for i := loIdx + 1; i < hiIdx; i++ {
   420  		removed += bits.OnesCount16(b[startIdx+i])
   421  		b[startIdx+i] = 0
   422  	}
   423  
   424  	if loIdx == hiIdx {
   425  		for p := loPos; p <= hiPos; p++ {
   426  			if b[startIdx+loIdx]&bitmapMask[p] > 0 {
   427  				removed++
   428  			}
   429  			b[startIdx+loIdx] &= ^bitmapMask[p]
   430  		}
   431  		setCardinality(b, N-removed)
   432  		return
   433  	}
   434  	for p := loPos; p < 1<<4; p++ {
   435  		if b[startIdx+loIdx]&bitmapMask[p] > 0 {
   436  			removed++
   437  		}
   438  		b[startIdx+loIdx] &= ^bitmapMask[p]
   439  	}
   440  	for p := uint16(0); p <= hiPos; p++ {
   441  		if b[startIdx+hiIdx]&bitmapMask[p] > 0 {
   442  			removed++
   443  		}
   444  		b[startIdx+hiIdx] &= ^bitmapMask[p]
   445  	}
   446  	setCardinality(b, N-removed)
   447  }
   448  
   449  func (b bitmap) has(x uint16) bool {
   450  	idx := x >> 4
   451  	pos := x & 0xF
   452  	has := b[startIdx+idx] & bitmapMask[pos]
   453  	return has > 0
   454  }
   455  
   456  func (b bitmap) rank(x uint16) int {
   457  	idx := x >> 4
   458  	pos := x & 0xF
   459  	if b[startIdx+idx]&bitmapMask[pos] == 0 {
   460  		return -1
   461  	}
   462  
   463  	var rank int
   464  	for i := 0; i < int(idx); i++ {
   465  		rank += bits.OnesCount16(b[int(startIdx)+i])
   466  	}
   467  	for p := uint16(0); p <= pos; p++ {
   468  		if b[startIdx+idx]&bitmapMask[p] > 0 {
   469  			rank++
   470  		}
   471  	}
   472  	return rank - 1
   473  }
   474  
   475  // TODO: This can perhaps be using SIMD instructions.
   476  func (b bitmap) andBitmap(other bitmap) []uint16 {
   477  	out := make([]uint16, maxContainerSize)
   478  	out[indexSize] = maxContainerSize
   479  	out[indexType] = typeBitmap
   480  	var num int
   481  	for i := int(startIdx); i < len(b); i++ {
   482  		out[i] = b[i] & other[i]
   483  		num += bits.OnesCount16(out[i])
   484  	}
   485  	setCardinality(out, num)
   486  	return out
   487  }
   488  
   489  func (b bitmap) orBitmap(other bitmap, buf []uint16, runMode int) []uint16 {
   490  	if runMode&runInline > 0 {
   491  		buf = b
   492  	} else {
   493  		copy(buf, b) // Copy over first.
   494  	}
   495  	buf[indexSize] = maxContainerSize
   496  	buf[indexType] = typeBitmap
   497  
   498  	if num := getCardinality(b); num == maxCardinality {
   499  		// do nothing. bitmap is already full.
   500  
   501  	} else if runMode&runLazy > 0 || num == invalidCardinality {
   502  		data := buf[startIdx:]
   503  		for i, v := range other[startIdx:] {
   504  			data[i] |= v
   505  		}
   506  		setCardinality(buf, invalidCardinality)
   507  
   508  	} else {
   509  		var num int
   510  		data := buf[startIdx:]
   511  		for i, v := range other[startIdx:] {
   512  			data[i] |= v
   513  			// We are going to iterate over the entire container. So, we can
   514  			// just recount the cardinality, starting from num=0.
   515  			num += bits.OnesCount16(data[i])
   516  		}
   517  		setCardinality(buf, num)
   518  	}
   519  	if runMode&runInline > 0 {
   520  		return nil
   521  	}
   522  	return buf
   523  }
   524  
   525  func (b bitmap) andNotBitmap(other bitmap) []uint16 {
   526  	var num int
   527  	data := b[startIdx:]
   528  	for i, v := range other[startIdx:] {
   529  		data[i] = data[i] ^ (data[i] & v)
   530  		num += bits.OnesCount16(data[i])
   531  	}
   532  	setCardinality(b, num)
   533  	return b
   534  }
   535  
   536  func (b bitmap) andNotArray(other array) []uint16 {
   537  	for _, e := range other.all() {
   538  		b.remove(e)
   539  	}
   540  	return b
   541  }
   542  
   543  func (b bitmap) orArray(other array, buf []uint16, runMode int) []uint16 {
   544  	if runMode&runInline > 0 {
   545  		buf = b
   546  	} else {
   547  		copy(buf, b)
   548  	}
   549  
   550  	if num := getCardinality(b); num == maxCardinality {
   551  		// do nothing. This bitmap is already full.
   552  
   553  	} else if runMode&runLazy > 0 || num == invalidCardinality {
   554  		// Avoid calculating the cardinality to speed up operations.
   555  		for _, x := range other.all() {
   556  			idx := x / 16
   557  			pos := x % 16
   558  
   559  			buf[startIdx+idx] |= bitmapMask[pos]
   560  		}
   561  		setCardinality(buf, invalidCardinality)
   562  
   563  	} else {
   564  		num := getCardinality(buf)
   565  		for _, x := range other.all() {
   566  			idx := x / 16
   567  			pos := x % 16
   568  
   569  			val := &buf[4+idx]
   570  			before := bits.OnesCount16(*val)
   571  			*val |= bitmapMask[pos]
   572  			after := bits.OnesCount16(*val)
   573  			num += after - before
   574  		}
   575  		setCardinality(buf, num)
   576  	}
   577  
   578  	if runMode&runInline > 0 {
   579  		return nil
   580  	}
   581  	return buf
   582  }
   583  
   584  func (b bitmap) all() []uint16 {
   585  	var res []uint16
   586  	data := b[startIdx:]
   587  	for idx := uint16(0); idx < uint16(len(data)); idx++ {
   588  		x := data[idx]
   589  		// TODO: This could potentially be optimized.
   590  		for pos := uint16(0); pos < 16; pos++ {
   591  			if x&bitmapMask[pos] > 0 {
   592  				res = append(res, (idx<<4)|pos)
   593  			}
   594  		}
   595  	}
   596  	return res
   597  }
   598  
   599  //TODO: It can be optimized.
   600  func (b bitmap) selectAt(idx int) uint16 {
   601  	data := b[startIdx:]
   602  	n := uint16(len(data))
   603  	for i := uint16(0); i < n; i++ {
   604  		x := data[i]
   605  		c := bits.OnesCount16(x)
   606  		if idx < c {
   607  			for pos := uint16(0); pos < 16; pos++ {
   608  				if idx == 0 && x&bitmapMask[pos] > 0 {
   609  					return i*16 + pos
   610  				}
   611  				if x&bitmapMask[pos] > 0 {
   612  					idx--
   613  				}
   614  			}
   615  
   616  		}
   617  		idx -= c
   618  	}
   619  	panic("should not reach here")
   620  }
   621  
   622  // bitValue returns a 0 or a 1 depending upon whether x is present in the bitmap, where 1 means
   623  // present and 0 means absent.
   624  func (b bitmap) bitValue(x uint16) uint16 {
   625  	idx := x >> 4
   626  	return (b[4+idx] >> (15 - (x & 0xF))) & 1
   627  }
   628  
   629  func (b bitmap) isFull() bool {
   630  	return false
   631  }
   632  
   633  func (b bitmap) minimum() uint16 {
   634  	N := getCardinality(b)
   635  	if N == 0 {
   636  		return 0
   637  	}
   638  	for i, x := range b[startIdx:] {
   639  		lz := bits.LeadingZeros16(x)
   640  		if lz == 16 {
   641  			continue
   642  		}
   643  		return uint16(16*i + lz)
   644  	}
   645  	panic("We shouldn't reach here")
   646  }
   647  
   648  func (b bitmap) maximum() uint16 {
   649  	N := getCardinality(b)
   650  	if N == 0 {
   651  		return 0
   652  	}
   653  	for i := len(b) - 1; i >= int(startIdx); i-- {
   654  		x := b[i]
   655  		tz := bits.TrailingZeros16(x)
   656  		if tz == 16 {
   657  			continue
   658  		}
   659  		return uint16(16*i + 15 - tz)
   660  	}
   661  	panic("We shouldn't reach here")
   662  }
   663  
   664  func (b bitmap) cardinality() int {
   665  	var num int
   666  	for _, x := range b[startIdx:] {
   667  		num += bits.OnesCount16(x)
   668  	}
   669  	return num
   670  }
   671  
   672  var zeroContainer = make([]uint16, maxContainerSize)
   673  
   674  func (b bitmap) zeroOut() {
   675  	setCardinality(b, 0)
   676  	copy(b[startIdx:], zeroContainer[startIdx:])
   677  }
   678  
   679  var (
   680  	runInline = 0x01
   681  	runLazy   = 0x02
   682  )
   683  
   684  func containerOr(ac, bc, buf []uint16, runMode int) []uint16 {
   685  	at := ac[indexType]
   686  	bt := bc[indexType]
   687  
   688  	if at == typeArray && bt == typeArray {
   689  		left := array(ac)
   690  		right := array(bc)
   691  		// We can't always inline this function. If the right container has
   692  		// enough entries, trying to do a union with the left container inplace
   693  		// could end up overwriting the left container entries. So, we use a
   694  		// buffer to hold all output, and then copy it over to left.
   695  		//
   696  		// TODO: If right doesn't have a lot of entries, we could just iterate
   697  		// over left and merge the entries from right inplace. Would be faster
   698  		// than copying over all entries into buffer. Worth trying that approach.
   699  		return left.orArray(right, buf, runMode)
   700  	}
   701  	if at == typeArray && bt == typeBitmap {
   702  		left := array(ac)
   703  		right := bitmap(bc)
   704  		// Don't run inline for this call.
   705  		return right.orArray(left, buf, runMode&^runInline)
   706  	}
   707  
   708  	// These two following cases can be fully inlined.
   709  	if at == typeBitmap && bt == typeArray {
   710  		left := bitmap(ac)
   711  		right := array(bc)
   712  		return left.orArray(right, buf, runMode)
   713  	}
   714  	if at == typeBitmap && bt == typeBitmap {
   715  		left := bitmap(ac)
   716  		right := bitmap(bc)
   717  		return left.orBitmap(right, buf, runMode)
   718  	}
   719  	panic("containerAnd: We should not reach here")
   720  }
   721  
   722  func containerAnd(ac, bc []uint16) []uint16 {
   723  	at := ac[indexType]
   724  	bt := bc[indexType]
   725  
   726  	if at == typeArray && bt == typeArray {
   727  		left := array(ac)
   728  		right := array(bc)
   729  		return left.andArray(right)
   730  	}
   731  	if at == typeArray && bt == typeBitmap {
   732  		left := array(ac)
   733  		right := bitmap(bc)
   734  		return left.andBitmap(right)
   735  	}
   736  	if at == typeBitmap && bt == typeArray {
   737  		left := bitmap(ac)
   738  		right := array(bc)
   739  		out := right.andBitmap(left)
   740  		return out
   741  	}
   742  	if at == typeBitmap && bt == typeBitmap {
   743  		left := bitmap(ac)
   744  		right := bitmap(bc)
   745  		return left.andBitmap(right)
   746  	}
   747  	panic("containerAnd: We should not reach here")
   748  }
   749  
   750  // TODO: Optimize this function.
   751  func containerAndNot(ac, bc, buf []uint16) []uint16 {
   752  	at := ac[indexType]
   753  	bt := bc[indexType]
   754  
   755  	if at == typeArray && bt == typeArray {
   756  		left := array(ac)
   757  		right := array(bc)
   758  		return left.andNotArray(right, buf)
   759  	}
   760  	if at == typeArray && bt == typeBitmap {
   761  		left := array(ac)
   762  		right := bitmap(bc)
   763  		return left.andNotBitmap(right, buf)
   764  	}
   765  	if at == typeBitmap && bt == typeArray {
   766  		left := bitmap(ac)
   767  		right := array(bc)
   768  		out := left.andNotArray(right)
   769  		return out
   770  	}
   771  	if at == typeBitmap && bt == typeBitmap {
   772  		left := bitmap(ac)
   773  		right := bitmap(bc)
   774  		return left.andNotBitmap(right)
   775  	}
   776  	panic("containerAndNot: We should not reach here")
   777  }