diff --git a/rbf/cursorx.go b/rbf/cursorx.go index 0ca291ff1..f1c8f338a 100644 --- a/rbf/cursorx.go +++ b/rbf/cursorx.go @@ -197,9 +197,9 @@ func intoContainer(l leafCell, tx *Tx, replacing *roaring.Container, target []by } c = roaring.RemakeContainerBitmap(replacing, cloneMaybe) case ContainerTypeBitmap: - c = roaring.RemakeContainerBitmap(replacing, toArray64(cpMaybe)) + c = roaring.RemakeContainerBitmapN(replacing, toArray64(cpMaybe), int32(l.BitN)) case ContainerTypeRLE: - c = roaring.RemakeContainerRun(replacing, toInterval16(cpMaybe)) + c = roaring.RemakeContainerRunN(replacing, toInterval16(cpMaybe), int32(l.BitN)) } // Note: If the "roaringparanoia" build tag isn't set, this // should be optimized away entirely. Otherwise it's moderately diff --git a/roaring/container_stash.go b/roaring/container_stash.go index 2cde05743..7dd6eae83 100644 --- a/roaring/container_stash.go +++ b/roaring/container_stash.go @@ -125,6 +125,8 @@ func NewContainer() *Container { return NewContainerArray(nil) } +// RemakeContainerBitmap overwrites the contents of c, which must not be +// frozen, with a provided bitmap, and computes a correct N. func RemakeContainerBitmap(c *Container, bitmap []uint64) *Container { *c = Container{typeID: ContainerBitmap} c.setBitmap(bitmap) @@ -132,15 +134,41 @@ func RemakeContainerBitmap(c *Container, bitmap []uint64) *Container { return c } +// RemakeContainerBitmapN uses the provided n instead of counting bits. The +// provided container must not be frozen. +func RemakeContainerBitmapN(c *Container, bitmap []uint64, n int32) *Container { + *c = Container{typeID: ContainerBitmap} + c.setBitmap(bitmap) + c.n = n + return c +} + +// RemakeContainerArray populates c with an array container using the provided +// array. It must not be used on a frozen container. func RemakeContainerArray(c *Container, array []uint16) *Container { *c = Container{typeID: ContainerArray} c.setArray(array) return c } +// RemakeContainerRun repopulates c with the provided intervals. c must not +// be frozen. func RemakeContainerRun(c *Container, intervals []Interval16) *Container { *c = Container{typeID: ContainerRun} c.setRuns(intervals) + c.n = 0 + for _, r := range intervals { + c.n += int32(r.Last - r.Start + 1) + } + return c +} + +// RemakeContainerRunN repopulates c with the provided intervals, but +// assumes the provided n is accurate. c must not be frozen. +func RemakeContainerRunN(c *Container, intervals []Interval16, n int32) *Container { + *c = Container{typeID: ContainerRun} + c.setRuns(intervals) + c.n = n return c }