func internalHll4Update()

in hll/hll_4update.go [25:120]


func internalHll4Update(h *hll4ArrayImpl, slotNo int, newValue int) error {
	var (
		actualOldValue     int
		shiftedNewValue    int //value - curMin
		curMin             = h.curMin
		rawStoredOldNibble = h.getNibble(slotNo)           // could be 0
		lb0nOldValue       = rawStoredOldNibble + h.curMin // provable lower bound, could be 0
		err                error
	)

	if newValue <= lb0nOldValue {
		return nil
	}

	// Based on whether we have an AUX_TOKEN and whether the shiftedNewValue is greater than
	// AUX_TOKEN, we have four cases for how to actually modify the data structure:
	// 1. (shiftedNewValue >= AUX_TOKEN) && (rawStoredOldNibble = AUX_TOKEN) //881:
	//    The byte array already contains aux token
	//    This is the case where old and new values are both exceptions.
	//    Therefore, the 4-bit array already is AUX_TOKEN. Only need to update auxMap
	// 2. (shiftedNewValue < AUX_TOKEN) && (rawStoredOldNibble = AUX_TOKEN) //885
	//    This is the (hypothetical) case where old value is an exception and the new one is not,
	//    which is impossible given that curMin has not changed here and the newValue > oldValue.
	// 3. (shiftedNewValue >= AUX_TOKEN) && (rawStoredOldNibble < AUX_TOKEN) //892
	//    This is the case where the old value is not an exception and the new value is.
	//    Therefore, the AUX_TOKEN must be stored in the 4-bit array and the new value
	//    added to the exception table.
	// 4. (shiftedNewValue < AUX_TOKEN) && (rawStoredOldNibble < AUX_TOKEN) //897
	//    This is the case where neither the old value nor the new value is an exception.
	//    Therefore, we just overwrite the 4-bit array with the shifted new value.

	if rawStoredOldNibble == auxToken { //846 Note: This is rare and really hard to test!
		if h.auxHashMap == nil {
			return fmt.Errorf("auxHashMap must already exist")
		}
		actualOldValue, err = h.auxHashMap.mustFindValueFor(slotNo)
		if newValue <= actualOldValue || err != nil {
			return err
		}
		// We know that the array will be changed, but we haven't actually updated yet.
		err := h.hipAndKxQIncrementalUpdate(actualOldValue, newValue)
		if err != nil {
			return err
		}
		shiftedNewValue = newValue - curMin
		if shiftedNewValue < 0 {
			return fmt.Errorf("shifedNewValue < 0")
		}
		if shiftedNewValue >= auxToken { //CASE 1:
			err := h.auxHashMap.mustReplace(slotNo, newValue)
			if err != nil {
				return err
			}
		} //else                         //CASE 2: impossible
	} else { //rawStoredOldNibble < AUX_TOKEN
		actualOldValue = lb0nOldValue
		// We know that the array will be changed, but we haven't actually updated yet.
		err := h.hipAndKxQIncrementalUpdate(actualOldValue, newValue)
		if err != nil {
			return err
		}
		shiftedNewValue = newValue - curMin
		if shiftedNewValue < 0 {
			return fmt.Errorf("shifedNewValue < 0")
		}
		if shiftedNewValue >= auxToken { //CASE 3: //892
			h.putNibble(slotNo, auxToken)
			if h.auxHashMap == nil {
				h.auxHashMap = h.getNewAuxHashMap()
			}
			err := h.auxHashMap.mustAdd(slotNo, newValue)
			if err != nil {
				return err
			}
		} else { // CASE 4: //897
			h.putNibble(slotNo, byte(shiftedNewValue))
		}
	}

	// We just changed the HLL array, so it might be time to change curMin.
	if actualOldValue == curMin {
		if h.numAtCurMin < 1 {
			return fmt.Errorf("h.numAtCurMin < 1")
		}
		h.numAtCurMin--
		for h.numAtCurMin == 0 {
			// Increases curMin by 1, and builds a new aux table,
			// shifts values in 4-bit table, and recounts curMin.
			err := shiftToBiggerCurMin(h)
			if err != nil {
				return err
			}
		}
	}
	return nil
}