hll/coupon_list.go (144 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" "fmt" ) type couponListImpl struct { hllSketchConfig hllCouponState } func (c *couponListImpl) GetCompositeEstimate() (float64, error) { return getEstimate(c) } func (c *couponListImpl) GetEstimate() (float64, error) { return getEstimate(c) } func (c *couponListImpl) GetHipEstimate() (float64, error) { return getEstimate(c) } func (c *couponListImpl) GetLowerBound(numStdDev int) (float64, error) { return getLowerBound(c, numStdDev) } func (c *couponListImpl) GetUpperBound(numStdDev int) (float64, error) { return getUpperBound(c, numStdDev) } func (c *couponListImpl) GetUpdatableSerializationBytes() int { return c.getMemDataStart() + (4 << c.getLgCouponArrInts()) } func (c *couponListImpl) ToCompactSlice() ([]byte, error) { return toCouponSlice(c, true) } func (c *couponListImpl) ToUpdatableSlice() ([]byte, error) { return toCouponSlice(c, false) } // couponUpdate updates the couponListImpl with the given coupon. // it returns the updated couponListImpl or a newly promoted couponHashSetImpl. func (c *couponListImpl) couponUpdate(coupon int) (hllSketchStateI, error) { length := 1 << c.lgCouponArrInts for i := 0; i < length; i++ { couponAtIdx := c.couponIntArr[i] if couponAtIdx == empty { c.couponIntArr[i] = coupon //update c.couponCount++ if c.couponCount >= length { if c.lgConfigK < 8 { return promoteListToHll(c) //oooFlag = false } return promoteListToSet(c) //oooFlag = true } return c, nil } //cell not empty if couponAtIdx == coupon { return c, nil //duplicate } //cell not empty & not a duplicate, continue } return nil, fmt.Errorf("array invalid: no empties & no duplicates") } // iterator returns an iterator over the couponListImpl. func (c *couponListImpl) iterator() pairIterator { return newIntArrayPairIterator(c.couponIntArr, c.lgConfigK) } func (c *couponListImpl) getMemDataStart() int { return listIntArrStart } func (c *couponListImpl) getPreInts() int { return listPreInts } func (c *couponListImpl) copyAs(tgtHllType TgtHllType) (hllSketchStateI, error) { newC := &couponListImpl{ hllSketchConfig: newHllSketchConfig(c.lgConfigK, tgtHllType, curModeList), hllCouponState: newHllCouponState(c.lgCouponArrInts, c.couponCount, make([]int, len(c.couponIntArr))), } copy(newC.couponIntArr, c.couponIntArr) return newC, nil } func (c *couponListImpl) copy() (hllSketchStateI, error) { return c.copyAs(c.tgtHllType) } func (c *couponListImpl) mergeTo(dest HllSketch) error { return mergeCouponTo(c, dest) } // promoteListToHll move coupons to an hllArray from couponListImpl func promoteListToHll(src *couponListImpl) (hllArray, error) { tgtHllArr, _ := newHllArray(src.lgConfigK, src.tgtHllType) srcIter := src.iterator() tgtHllArr.putKxQ0(float64(uint64(1) << src.lgConfigK)) for srcIter.nextValid() { p, err := srcIter.getPair() if err != nil { return nil, err } _, err = tgtHllArr.couponUpdate(p) if err != nil { return nil, err } } est, err := src.GetEstimate() if err != nil { return nil, err } tgtHllArr.putHipAccum(est) tgtHllArr.putOutOfOrder(false) return tgtHllArr, nil } // promoteListToSet move coupons to a couponHashSetImpl from couponListImpl func promoteListToSet(c *couponListImpl) (hllSketchStateI, error) { couponCount := c.getCouponCount() arr := c.couponIntArr chSet, err := newCouponHashSet(c.lgConfigK, c.tgtHllType) if err != nil { return nil, err } for i := 0; i < couponCount && err == nil; i++ { _, err = chSet.couponUpdate(arr[i]) } if err != nil { return nil, err } return &chSet, nil } // newCouponList returns a new couponListImpl. func newCouponList(lgConfigK int, tgtHllType TgtHllType, curMode curMode) (couponListImpl, error) { var ( lgCouponArrInts = lgInitSetSize //SET ) if curMode == curModeList { lgCouponArrInts = lgInitListSize } else if lgConfigK <= 7 { return couponListImpl{}, fmt.Errorf("lgConfigK must be > 7 for non-HLL mode") } couponIntArr := make([]int, 1<<lgCouponArrInts) couponCount := 0 return couponListImpl{ hllSketchConfig: newHllSketchConfig(lgConfigK, tgtHllType, curMode), hllCouponState: newHllCouponState(lgCouponArrInts, couponCount, couponIntArr), }, nil } // deserializeCouponList returns a new couponListImpl from the given byte slice. func deserializeCouponList(byteArray []byte) (hllCoupon, error) { lgConfigK := extractLgK(byteArray) tgtHllType := extractTgtHllType(byteArray) list, err := newCouponList(lgConfigK, tgtHllType, curModeList) if err != nil { return nil, err } couponCount := extractListCount(byteArray) // TODO there must be a more efficient to reinterpret the byte array as an int array for it := 0; it < couponCount; it++ { list.couponIntArr[it] = int(binary.LittleEndian.Uint32(byteArray[listIntArrStart+it*4 : listIntArrStart+it*4+4])) } list.couponCount = couponCount return &list, nil }