hll/preamble_utils.go (205 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 ( "encoding/binary" "math" "github.com/apache/datasketches-go/internal" ) const ( preambleIntsBytes = 0 serVerByte = 1 familyByte = 2 lgKByte = 3 lgArrByte = 4 flagsByte = 5 listCountByte = 6 hllCurMinByte = 6 // modeByte // mode encoding of combined curMode and TgtHllType: // Dec Lo4Bits TgtHllType, curMode // 0 0000 HLL_4, LIST // 1 0001 HLL_4, SET // 2 0010 HLL_4, HLL // 4 0100 HLL_6, LIST // 5 0101 HLL_6, SET // 6 0110 HLL_6, HLL // 8 1000 HLL_8, LIST // 9 1001 HLL_8, SET // 10 1010 HLL_8, HLL modeByte = 7 //lo2bits = curMode, next 2 bits = tgtHllType listIntArrStart = 8 ) const ( //Coupon Hash Set hashSetCountInt = 8 hashSetIntArrStart = 12 ) const ( // HLL hipAccumDouble = 8 kxq0Double = 16 kxq1Double = 24 curMinCountInt = 32 auxCountInt = 36 hllByteArrStart = 40 ) const ( //Flag bit masks emptyFlagMask = 4 compactFlagMask = 8 outOfOrderFlagMask = 16 rebuildCurminNumKxqMask = 32 ) const ( //Mode byte masks curModeMask = 3 tgtHllTypeMask = 12 ) const ( // Other constants serVer = 1 familyId = 7 listPreInts = 2 hashSetPreInts = 3 hllPreInts = 10 ) func extractPreInts(byteArr []byte) int { return int(byteArr[preambleIntsBytes] & 0x3F) } func extractSerVer(byteArr []byte) int { return int((byteArr[serVerByte]) & 0xFF) } func extractFamilyID(byteArr []byte) int { return int((byteArr[familyByte]) & 0xFF) } func extractCurMode(byteArr []byte) curMode { return curMode(byteArr[modeByte] & curModeMask) } func extractTgtHllType(byteArr []byte) TgtHllType { typeId := byteArr[modeByte] & tgtHllTypeMask return TgtHllType(typeId >> 2) } func extractLgK(byteArr []byte) int { return int(byteArr[lgKByte] & 0xFF) } func extractListCount(byteArr []byte) int { return int(byteArr[listCountByte] & 0xFF) } func extractCompactFlag(byteArr []byte) bool { return (int(byteArr[flagsByte]) & compactFlagMask) > 0 } func extractHashSetCount(byteArr []byte) int { return int(binary.LittleEndian.Uint32(byteArr[hashSetCountInt : hashSetCountInt+4])) } func extractLgArr(byteArr []byte) int { return int(byteArr[lgArrByte] & 0xFF) } func extractOooFlag(byteArr []byte) bool { flags := byteArr[flagsByte] return (flags & outOfOrderFlagMask) > 0 } func extractCurMin(byteArr []byte) int { return int(byteArr[hllCurMinByte] & 0xFF) } func extractHipAccum(byteArr []byte) float64 { return math.Float64frombits(binary.LittleEndian.Uint64(byteArr[hipAccumDouble : hipAccumDouble+8])) } func extractKxQ0(byteArr []byte) float64 { return math.Float64frombits(binary.LittleEndian.Uint64(byteArr[kxq0Double : kxq0Double+8])) } func extractKxQ1(byteArr []byte) float64 { return math.Float64frombits(binary.LittleEndian.Uint64(byteArr[kxq1Double : kxq1Double+8])) } func extractNumAtCurMin(byteArr []byte) int { return int(binary.LittleEndian.Uint32(byteArr[curMinCountInt : curMinCountInt+4])) } func extractRebuildCurMinNumKxQFlag(byteArr []byte) bool { return (byteArr[flagsByte] & rebuildCurminNumKxqMask) > 0 } func extractAuxCount(byteArr []byte) int { return int(binary.LittleEndian.Uint32(byteArr[auxCountInt : auxCountInt+4])) } func computeLgArr(byteArr []byte, couponCount int, lgConfigK int) (int, error) { //value is missing, recompute curMode := extractCurMode(byteArr) if curMode == curModeList { return lgInitListSize, nil } ceilPwr2 := internal.CeilPowerOf2(couponCount) if (resizeDenom * couponCount) > (resizeNumber * ceilPwr2) { ceilPwr2 <<= 1 } if curMode == curModeSet { v, err := internal.ExactLog2(ceilPwr2) return max(lgInitSetSize, v), err } //only used for HLL4 v, err := internal.ExactLog2(ceilPwr2) return max(lgAuxArrInts[lgConfigK], v), err } func insertAuxCount(byteArr []byte, auxCount int) error { binary.LittleEndian.PutUint32(byteArr[auxCountInt:auxCountInt+4], uint32(auxCount)) return nil } func insertListCount(byteArr []byte, listCnt int) { byteArr[listCountByte] = byte(listCnt) } func insertHashSetCount(byteArr []byte, hashSetCnt int) { binary.LittleEndian.PutUint32(byteArr[hashSetCountInt:hashSetCountInt+4], uint32(hashSetCnt)) } func insertPreInts(byteArr []byte, preInts int) { byteArr[preambleIntsBytes] = byte(preInts & 0x3F) } func insertSerVer(byteArr []byte) { byteArr[serVerByte] = byte(serVer) } func insertFamilyID(byteArr []byte) { byteArr[familyByte] = byte(familyId) } func insertLgK(byteArr []byte, lgK int) { byteArr[lgKByte] = byte(lgK) } func insertLgArr(byteArr []byte, lgArr int) { byteArr[lgArrByte] = byte(lgArr) } func insertEmptyFlag(byteArr []byte, emptyFlag bool) { flags := byteArr[flagsByte] if emptyFlag { flags |= emptyFlagMask } else { flags &= ^uint8(emptyFlagMask) } byteArr[flagsByte] = flags } func insertOooFlag(byteArr []byte, oooFlag bool) { flags := byteArr[flagsByte] if oooFlag { flags |= outOfOrderFlagMask } else { flags &= ^uint8(outOfOrderFlagMask) } byteArr[flagsByte] = flags } func insertCurMode(byteArr []byte, curMode curMode) { mode := byteArr[modeByte] & ^uint8(curModeMask) mode |= uint8(curMode) & curModeMask byteArr[modeByte] = mode } func insertTgtHllType(byteArr []byte, tgtHllType TgtHllType) { mode := byteArr[modeByte] & ^uint8(tgtHllTypeMask) mode |= (uint8(tgtHllType) << 2) & tgtHllTypeMask byteArr[modeByte] = mode } func insertCompactFlag(byteArr []byte, compactFlag bool) { flags := byteArr[flagsByte] if compactFlag { flags |= compactFlagMask } else { flags &= ^uint8(compactFlagMask) } byteArr[flagsByte] = flags } func insertCurMin(byteArr []byte, curMin int) { byteArr[hllCurMinByte] = byte(curMin) } func insertHipAccum(byteArr []byte, hipAccum float64) { binary.LittleEndian.PutUint64(byteArr[hipAccumDouble:hipAccumDouble+8], math.Float64bits(hipAccum)) } func insertKxQ0(byteArr []byte, kxq0 float64) { binary.LittleEndian.PutUint64(byteArr[kxq0Double:kxq0Double+8], math.Float64bits(kxq0)) } func insertKxQ1(byteArr []byte, kxq1 float64) { binary.LittleEndian.PutUint64(byteArr[kxq1Double:kxq1Double+8], math.Float64bits(kxq1)) } func insertNumAtCurMin(byteArr []byte, numAtCurMin int) { binary.LittleEndian.PutUint32(byteArr[curMinCountInt:curMinCountInt+4], uint32(numAtCurMin)) } func insertRebuildCurMinNumKxQFlag(byteArr []byte, rebuild bool) { flags := byteArr[flagsByte] if rebuild { flags |= rebuildCurminNumKxqMask } else { flags &= ^uint8(rebuildCurminNumKxqMask) } byteArr[flagsByte] = flags }