hll/hll_8array.go (139 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hll
import (
"fmt"
)
// hll8ArrayImpl Uses 6 bits per slot in a packed byte array
type hll8ArrayImpl struct {
hllArrayImpl
}
type hll8Iterator struct {
hllPairIterator
hll *hll8ArrayImpl
}
func (h *hll8ArrayImpl) iterator() pairIterator {
a := newHll8Iterator(1<<h.lgConfigK, h)
return &a
}
func (h *hll8ArrayImpl) copyAs(tgtHllType TgtHllType) (hllSketchStateI, error) {
if tgtHllType == h.tgtHllType {
return h.copy()
}
if tgtHllType == TgtHllTypeHll4 {
return convertToHll4(h)
}
if tgtHllType == TgtHllTypeHll6 {
return convertToHll6(h)
}
return nil, fmt.Errorf("cannot convert to TgtHllType id: %d", int(tgtHllType))
}
func (h *hll8ArrayImpl) copy() (hllSketchStateI, error) {
return &hll8ArrayImpl{
hllArrayImpl: h.copyCommon(),
}, nil
}
func (h *hll8ArrayImpl) ToCompactSlice() ([]byte, error) {
return h.ToUpdatableSlice()
}
func (h *hll8ArrayImpl) ToUpdatableSlice() ([]byte, error) {
return toHllByteArr(h, false)
}
// newHll8Array returns a new Hll8Array.
func newHll8Array(lgConfigK int) hllArray {
return &hll8ArrayImpl{
hllArrayImpl: hllArrayImpl{
hllSketchConfig: newHllSketchConfig(lgConfigK, TgtHllTypeHll8, curModeHll),
curMin: 0,
numAtCurMin: 1 << lgConfigK,
hipAccum: 0,
kxq0: float64(uint64(1 << lgConfigK)),
kxq1: 0,
hllByteArr: make([]byte, 1<<lgConfigK),
auxStart: hllByteArrStart + 1<<(lgConfigK-1),
},
}
}
// deserializeHll8 returns a new Hll8Array from the given byte array.
func deserializeHll8(byteArray []byte) hllArray {
lgConfigK := extractLgK(byteArray)
hll8 := newHll8Array(lgConfigK)
hll8.extractCommonHll(byteArray)
return hll8
}
func convertToHll8(srcAbsHllArr hllArray) (hllSketchStateI, error) {
lgConfigK := srcAbsHllArr.GetLgConfigK()
hll8Array := newHll8Array(lgConfigK)
hll8Array.putOutOfOrder(srcAbsHllArr.isOutOfOrder())
numZeros := 1 << lgConfigK
itr := srcAbsHllArr.iterator()
for itr.nextAll() {
v, err := itr.getValue()
if err != nil {
return nil, err
}
if v != empty {
numZeros--
p, err := itr.getPair()
if err != nil {
return nil, err
}
_, err = hll8Array.couponUpdate(p) //creates KxQ registers
if err != nil {
return nil, err
}
}
}
hll8Array.putNumAtCurMin(numZeros)
hll8Array.putHipAccum(srcAbsHllArr.getHipAccum()) //intentional overwrite
hll8Array.putRebuildCurMinNumKxQFlag(false)
return hll8Array, nil
}
func (h *hll8ArrayImpl) couponUpdate(coupon int) (hllSketchStateI, error) {
newValue := coupon >> keyBits26
slotNo := coupon & h.slotNoMask
err := h.updateSlotWithKxQ(slotNo, newValue)
return h, err
}
func (h *hll8ArrayImpl) updateSlotWithKxQ(slotNo int, newValue int) error {
oldValue := h.getSlotValue(slotNo)
if newValue > oldValue {
h.hllByteArr[slotNo] = byte(newValue & valMask6)
err := h.hipAndKxQIncrementalUpdate(oldValue, newValue)
if err != nil {
return err
}
if oldValue == 0 {
h.numAtCurMin-- //interpret numAtCurMin as num Zeros
if h.numAtCurMin < 0 {
return fmt.Errorf("numAtCurMin < 0")
}
}
}
return nil
}
func (h *hll8ArrayImpl) updateSlotNoKxQ(slotNo int, newValue int) {
oldValue := h.getSlotValue(slotNo)
h.hllByteArr[slotNo] = byte(max(newValue, oldValue))
}
func (h *hll8ArrayImpl) getSlotValue(slotNo int) int {
return int(h.hllByteArr[slotNo] & valMask6)
}
func newHll8Iterator(lengthPairs int, hll *hll8ArrayImpl) hll8Iterator {
return hll8Iterator{
hllPairIterator: newHllPairIterator(lengthPairs),
hll: hll,
}
}
func (h *hll8Iterator) nextValid() bool {
for h.index+1 < h.lengthPairs {
h.index++
h.value = int(h.hll.hllByteArr[h.index]) & valMask6
if h.value != empty {
return true
}
}
return false
}
func (h *hll8Iterator) getValue() (int, error) {
return int(h.hll.hllByteArr[h.index]) & valMask6, nil
}
func (h *hll8Iterator) getPair() (int, error) {
v, err := h.getValue()
return pair(h.index, v), err
}