@@ -130,7 +130,7 @@ func andNotContainers(a, b, res *Bitmap, optBuf []uint16) {
130130 bi , bn := 0 , b .keys .numKeys ()
131131
132132 akToAc := map [uint64 ][]uint16 {}
133- sizeContainers := uint64 ( 0 )
133+ sizeContainers := 0
134134 newKeys := 0
135135
136136 for ai < an && bi < bn {
@@ -154,7 +154,7 @@ func andNotContainers(a, b, res *Bitmap, optBuf []uint16) {
154154 ac := a .getContainer (off )
155155 if getCardinality (ac ) > 0 {
156156 akToAc [ak ] = ac
157- sizeContainers += uint64 ( len (ac ) )
157+ sizeContainers += len (ac )
158158 newKeys ++
159159 }
160160 ai ++
@@ -168,18 +168,13 @@ func andNotContainers(a, b, res *Bitmap, optBuf []uint16) {
168168 if getCardinality (ac ) > 0 {
169169 ak := a .keys .key (ai )
170170 akToAc [ak ] = ac
171- sizeContainers += uint64 ( len (ac ) )
171+ sizeContainers += len (ac )
172172 newKeys ++
173173 }
174174 }
175175
176176 if sizeContainers > 0 {
177- // 2x uint64 = 8x uint16; for key and offset; twice as much as actually needed
178- sizeKeys := 8 * uint64 (newKeys ) * 2
179- // ensure enough space for new containers and keys,
180- // allocate required memory just once to avoid copying underlying data slice multiple times
181- res .expandNoLengthChange (sizeContainers + sizeKeys )
182- res .expandKeys (sizeKeys )
177+ res .expandConditionally (newKeys , sizeContainers )
183178
184179 for ak , ac := range akToAc {
185180 // create a new container and update the key offset to this container.
@@ -290,7 +285,7 @@ func orContainers(a, b, res *Bitmap, buf []uint16) {
290285
291286 akToAc := map [uint64 ][]uint16 {}
292287 bkToBc := map [uint64 ][]uint16 {}
293- sizeContainers := uint64 ( 0 )
288+ sizeContainers := 0
294289 newKeys := 0
295290
296291 for ai < an && bi < bn {
@@ -318,7 +313,7 @@ func orContainers(a, b, res *Bitmap, buf []uint16) {
318313 ac := a .getContainer (off )
319314 if getCardinality (ac ) > 0 {
320315 akToAc [ak ] = ac
321- sizeContainers += uint64 ( len (ac ) )
316+ sizeContainers += len (ac )
322317 newKeys ++
323318 }
324319 ai ++
@@ -327,7 +322,7 @@ func orContainers(a, b, res *Bitmap, buf []uint16) {
327322 bc := b .getContainer (off )
328323 if getCardinality (bc ) > 0 {
329324 bkToBc [bk ] = bc
330- sizeContainers += uint64 ( len (bc ) )
325+ sizeContainers += len (bc )
331326 newKeys ++
332327 }
333328 bi ++
@@ -339,7 +334,7 @@ func orContainers(a, b, res *Bitmap, buf []uint16) {
339334 if getCardinality (ac ) > 0 {
340335 ak := a .keys .key (ai )
341336 akToAc [ak ] = ac
342- sizeContainers += uint64 ( len (ac ) )
337+ sizeContainers += len (ac )
343338 newKeys ++
344339 }
345340 }
@@ -349,18 +344,13 @@ func orContainers(a, b, res *Bitmap, buf []uint16) {
349344 if getCardinality (bc ) > 0 {
350345 bk := b .keys .key (bi )
351346 bkToBc [bk ] = bc
352- sizeContainers += uint64 ( len (bc ) )
347+ sizeContainers += len (bc )
353348 newKeys ++
354349 }
355350 }
356351
357352 if sizeContainers > 0 {
358- // 2x uint64 = 8x uint16; for key and offset; twice as much as actually needed
359- sizeKeys := 8 * uint64 (newKeys ) * 2
360- // ensure enough space for new containers and keys,
361- // allocate required memory just once avoid copying underlying data slice multiple times
362- res .expandNoLengthChange (sizeContainers + sizeKeys )
363- res .expandKeys (sizeKeys )
353+ res .expandConditionally (newKeys , sizeContainers )
364354
365355 for ak , ac := range akToAc {
366356 // create a new container and update the key offset to this container.
@@ -395,7 +385,7 @@ func orContainersInRange(a, b *Bitmap, bi, bn int, buf []uint16) {
395385 // copy containers from b to a all at once
396386 // expanding underlying data slice and keys subslice once
397387 bkToBc := map [uint64 ][]uint16 {}
398- sizeContainers := uint64 ( 0 )
388+ sizeContainers := 0
399389 newKeys := 0
400390
401391 for ai < an && bi < bn {
@@ -435,7 +425,7 @@ func orContainersInRange(a, b *Bitmap, bi, bn int, buf []uint16) {
435425 bc := b .getContainer (off )
436426 if getCardinality (bc ) > 0 {
437427 bkToBc [bk ] = bc
438- sizeContainers += uint64 ( len (bc ) )
428+ sizeContainers += len (bc )
439429 newKeys ++
440430 }
441431 bi ++
@@ -447,23 +437,13 @@ func orContainersInRange(a, b *Bitmap, bi, bn int, buf []uint16) {
447437 if getCardinality (bc ) > 0 {
448438 bk := b .keys .key (bi )
449439 bkToBc [bk ] = bc
450- sizeContainers += uint64 ( len (bc ) )
440+ sizeContainers += len (bc )
451441 newKeys ++
452442 }
453443 }
454444
455445 if sizeContainers > 0 {
456- if a .keysExpansionRequired (newKeys ) {
457- // 2x uint64 = 8x uint16; for key and offset; twice as much as actually needed
458- sizeKeys := 8 * uint64 (newKeys ) * 2
459-
460- // ensure enough space for new containers and keys,
461- // allocate required memory just once to avoid copying underlying data slice multiple times
462- a .expandNoLengthChange (sizeContainers + sizeKeys )
463- a .expandKeys (sizeKeys )
464- } else {
465- a .expandNoLengthChange (sizeContainers )
466- }
446+ a .expandConditionally (newKeys , sizeContainers )
467447
468448 for bk , bc := range bkToBc {
469449 // create a new container and update the key offset to this container.
@@ -498,36 +478,26 @@ func (ra *Bitmap) OrConc(bm *Bitmap, maxConcurrency int) *Bitmap {
498478 return ra
499479 }
500480
501- var totalSizeContainers uint64
502481 var totalNewKeys int
482+ var totalSizeContainers int
503483 var allKeys []uint64
504484 var allContainers [][]uint16
505485 lock := new (sync.Mutex )
506486 inlineVsMutateLock := new (sync.RWMutex )
507487 callback := func (bi , bj , _ int ) {
508488 buf := make ([]uint16 , maxContainerSize )
509- sizeContainers , newKeys , keys , containers := orContainersInRangeConc (ra , bm , bi , bj , buf , inlineVsMutateLock )
489+ newKeys , sizeContainers , keys , containers := orContainersInRangeConc (ra , bm , bi , bj , buf , inlineVsMutateLock )
510490
511491 lock .Lock ()
512- totalSizeContainers += sizeContainers
513492 totalNewKeys += newKeys
493+ totalSizeContainers += sizeContainers
514494 allKeys = append (allKeys , keys ... )
515495 allContainers = append (allContainers , containers ... )
516496 lock .Unlock ()
517497 }
518498 concurrentlyInRanges (numContainers , concurrency , callback )
519499 if totalSizeContainers > 0 {
520- if ra .keysExpansionRequired (totalNewKeys ) {
521- // 2x uint64 = 8x uint16; for key and offset; twice as much as actually needed
522- totalSizeKeys := 8 * uint64 (totalNewKeys ) * 2
523-
524- // ensure enough space for new containers and keys,
525- // allocate required memory just once to avoid copying underlying data slice multiple times
526- ra .expandNoLengthChange (totalSizeContainers + totalSizeKeys )
527- ra .expandKeys (totalSizeKeys )
528- } else {
529- ra .expandNoLengthChange (totalSizeContainers )
530- }
500+ ra .expandConditionally (totalNewKeys , totalSizeContainers )
531501
532502 for i , container := range allContainers {
533503 // create a new container and update the key offset to this container.
@@ -541,7 +511,7 @@ func (ra *Bitmap) OrConc(bm *Bitmap, maxConcurrency int) *Bitmap {
541511}
542512
543513func orContainersInRangeConc (a , b * Bitmap , bi , bn int , buf []uint16 , inlineVsMutateLock * sync.RWMutex ,
544- ) (sizeContainers uint64 , newKeys int , bKeys []uint64 , bContainers [][]uint16 ) {
514+ ) (newKeys , sizeContainers int , bKeys []uint64 , bContainers [][]uint16 ) {
545515 bk := b .keys .key (bi )
546516 ai := a .keys .search (bk )
547517 an := a .keys .numKeys ()
@@ -597,7 +567,7 @@ func orContainersInRangeConc(a, b *Bitmap, bi, bn int, buf []uint16, inlineVsMut
597567 if getCardinality (bc ) > 0 {
598568 bKeys = append (bKeys , bk )
599569 bContainers = append (bContainers , bc )
600- sizeContainers += uint64 ( len (bc ) )
570+ sizeContainers += len (bc )
601571 newKeys ++
602572 }
603573 bi ++
@@ -610,7 +580,7 @@ func orContainersInRangeConc(a, b *Bitmap, bi, bn int, buf []uint16, inlineVsMut
610580 bk := b .keys .key (bi )
611581 bKeys = append (bKeys , bk )
612582 bContainers = append (bContainers , bc )
613- sizeContainers += uint64 ( len (bc ) )
583+ sizeContainers += len (bc )
614584 newKeys ++
615585 }
616586 }
@@ -914,15 +884,7 @@ func (ra *Bitmap) FillUp(maxX uint64) {
914884 }
915885
916886 // calculate required memory to allocate and expand underlying slice
917- containersLen := uint64 (requiredContainersCount * maxContainerSize )
918- if ra .keysExpansionRequired (requiredContainersCount ) {
919- // 2x uint64 = 8x uint16; for key and offset; twice as much as actually needed
920- keysLen := uint64 (requiredContainersCount * 2 * 4 ) * 2
921- ra .expandNoLengthChange (containersLen + keysLen )
922- ra .expandKeys (keysLen )
923- } else {
924- ra .expandNoLengthChange (containersLen )
925- }
887+ ra .expandConditionally (requiredContainersCount , requiredContainersCount * maxContainerSize )
926888
927889 var onesBitmap bitmap
928890 if containerIdx < maxContainersCount {
@@ -1069,6 +1031,65 @@ func (b bitmap) fillWithOnes() {
10691031 }
10701032}
10711033
1072- func (ra * Bitmap ) keysExpansionRequired (newKeys int ) bool {
1073- return ra .keys .numKeys ()+ newKeys >= ra .keys .maxKeys ()
1034+ func (ra * Bitmap ) expandConditionally (newKeys int , sizeContainers int ) {
1035+ cp := cap (ra .data )
1036+ ln := len (ra .data )
1037+
1038+ sizeKeys := 8 * newKeys // 2x uint64 (key+offset) = 8x uint16
1039+ if ra .keys .numKeys ()+ newKeys < ra .keys .maxKeys () {
1040+ if ln + sizeContainers <= cp {
1041+ // keys and containers fit. nothing to do
1042+ return
1043+ }
1044+ // keys fit, containers do not. expand slice to make room for containers and only new keys
1045+ } else {
1046+ if ln + sizeKeys + sizeContainers <= cp {
1047+ curNumKeys := ra .keys .numKeys ()
1048+
1049+ // keys do not fit, containers do. just move containers to make room for keys
1050+ if curNumKeys > newKeys {
1051+ // make room for up to curNumKeys additional keys
1052+ sizeKeys = 8 * curNumKeys // 2x uint64 (key+offset) = 8x uint16
1053+ if left := cp - ln - sizeContainers ; left < sizeKeys {
1054+ sizeKeys = left / 8 * 8
1055+ }
1056+ }
1057+
1058+ // new containers will fit. just move containers to make room for keys
1059+ curSizeKeys := ra .keys .size ()
1060+ newSizeKeys := curSizeKeys + sizeKeys
1061+
1062+ ra .data = ra .data [:ln + sizeKeys ]
1063+ n := copy (ra .data [newSizeKeys :], ra .data [curSizeKeys :])
1064+ ra .memMoved += n
1065+ Memclr (ra .data [curSizeKeys :newSizeKeys ]) // Zero out the space in the middle.
1066+
1067+ ra .keys = uint16To64SliceUnsafe (ra .data [:newSizeKeys ])
1068+ ra .keys .setNodeSize (newSizeKeys )
1069+ for i := 0 ; i < curNumKeys ; i ++ {
1070+ ra .keys .setAt (valOffset (i ), ra .keys .val (i )+ uint64 (sizeKeys ))
1071+ }
1072+ return
1073+ }
1074+ // neither keys nor containers fit. expand slice to make room for containers and more keys
1075+ sizeKeys = 8 * max (newKeys , ra .keys .numKeys ()) // 2x uint64 (key+offset) = 8x uint16
1076+ }
1077+
1078+ // expand 2x (or up to sizeKeys+sizeNewContainers if 2x is too little)
1079+ growBy := max (cp , sizeKeys + sizeContainers )
1080+ out := make ([]uint16 , ln + sizeKeys , cp + growBy )
1081+
1082+ curSizeKeys := ra .keys .size ()
1083+ newSizeKeys := curSizeKeys + sizeKeys
1084+ copy (out , ra .data [:curSizeKeys ])
1085+ copy (out [newSizeKeys :], ra .data [curSizeKeys :])
1086+ ra .data = out
1087+ ra ._ptr = nil // Allow Go to GC whatever this was pointing to.
1088+ // Re-reference ra.keys correctly because underlying array has changed.
1089+
1090+ ra .keys = uint16To64SliceUnsafe (ra .data [:newSizeKeys ])
1091+ ra .keys .setNodeSize (newSizeKeys )
1092+ for i := 0 ; i < ra .keys .numKeys (); i ++ {
1093+ ra .keys .setAt (valOffset (i ), ra .keys .val (i )+ uint64 (sizeKeys ))
1094+ }
10741095}
0 commit comments