blob: 970a0f97a87b0f6be572c9148c55e8f3ec68b54e [file] [log] [blame]
/*
* 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 org.apache.datasketches.hll;
import static org.apache.datasketches.hll.HllUtil.AUX_TOKEN;
import static org.apache.datasketches.hll.HllUtil.KEY_BITS_26;
import static org.apache.datasketches.hll.HllUtil.LG_AUX_ARR_INTS;
import static org.apache.datasketches.hll.HllUtil.hiNibbleMask;
import static org.apache.datasketches.hll.HllUtil.loNibbleMask;
import static org.apache.datasketches.hll.HllUtil.noWriteAccess;
import static org.apache.datasketches.hll.PreambleUtil.HLL_BYTE_ARR_START;
import static org.apache.datasketches.hll.PreambleUtil.extractAuxCount;
import static org.apache.datasketches.hll.PreambleUtil.extractCompactFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertAuxCount;
import static org.apache.datasketches.hll.PreambleUtil.insertCompactFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertInt;
import static org.apache.datasketches.hll.PreambleUtil.insertLgArr;
import org.apache.datasketches.SketchesStateException;
import org.apache.datasketches.memory.Memory;
import org.apache.datasketches.memory.WritableMemory;
/**
* @author Lee Rhodes
*/
final class DirectHll4Array extends DirectHllArray {
//Called by HllSketch.writableWrap(), DirectCouponList.promoteListOrSetToHll
DirectHll4Array(final int lgConfigK, final WritableMemory wmem) {
super(lgConfigK, TgtHllType.HLL_4, wmem);
if (extractAuxCount(mem) > 0) {
putAuxHashMap(new DirectAuxHashMap(this, false), false);
}
}
//Called by HllSketch.wrap(Memory)
DirectHll4Array(final int lgConfigK, final Memory mem) {
super(lgConfigK, TgtHllType.HLL_4, mem);
final int auxCount = extractAuxCount(mem);
if (auxCount > 0) {
final boolean compact = extractCompactFlag(mem);
final AuxHashMap auxHashMap;
if (compact) {
auxHashMap = HeapAuxHashMap.heapify(mem, auxStart, lgConfigK, auxCount, compact);
} else {
auxHashMap = new DirectAuxHashMap(this, false); //not compact
}
putAuxHashMap(auxHashMap, compact);
}
}
@Override
HllSketchImpl copy() {
return Hll4Array.heapify(mem);
}
@Override
HllSketchImpl couponUpdate(final int coupon) {
if (wmem == null) { noWriteAccess(); }
final int newValue = coupon >>> KEY_BITS_26;
final int configKmask = (1 << getLgConfigK()) - 1;
final int slotNo = coupon & configKmask;
updateSlotWithKxQ(slotNo, newValue);
return this;
}
@Override
int getHllByteArrBytes() {
return hll4ArrBytes(lgConfigK);
}
@Override
int getNibble(final int slotNo) {
final long offset = HLL_BYTE_ARR_START + (slotNo >>> 1);
int theByte = mem.getByte(offset);
if ((slotNo & 1) > 0) { //odd?
theByte >>>= 4;
}
return theByte & loNibbleMask;
}
@Override
int getSlotValue(final int slotNo) {
final int nib = getNibble(slotNo);
if (nib == AUX_TOKEN) {
final AuxHashMap auxHashMap = getAuxHashMap();
return auxHashMap.mustFindValueFor(slotNo); //auxHashMap cannot be null here
} else {
return nib + getCurMin();
}
}
@Override
int getUpdatableSerializationBytes() {
final AuxHashMap auxHashMap = getAuxHashMap();
final int auxBytes;
if (auxHashMap == null) {
auxBytes = 4 << LG_AUX_ARR_INTS[lgConfigK];
} else {
auxBytes = 4 << auxHashMap.getLgAuxArrInts();
}
return HLL_BYTE_ARR_START + getHllByteArrBytes() + auxBytes;
}
@Override
PairIterator iterator() {
return new DirectHll4Iterator(1 << lgConfigK);
}
@Override
void putNibble(final int slotNo, final int nibValue) {
final long offset = HLL_BYTE_ARR_START + (slotNo >>> 1);
final int oldValue = mem.getByte(offset);
final byte value = ((slotNo & 1) == 0) //even?
? (byte) ((oldValue & hiNibbleMask) | (nibValue & loNibbleMask)) //set low nibble
: (byte) ((oldValue & loNibbleMask) | ((nibValue << 4) & hiNibbleMask)); //set high nibble
wmem.putByte(offset, value);
}
@Override
//Would be used by Union, but not used because the gadget is always HLL8 type
void updateSlotNoKxQ(final int slotNo, final int newValue) {
throw new SketchesStateException("Improper access.");
}
@Override
//Used by this couponUpdate()
//updates HipAccum, CurMin, NumAtCurMin, KxQs and checks newValue > oldValue
void updateSlotWithKxQ(final int slotNo, final int newValue) {
Hll4Update.internalHll4Update(this, slotNo, newValue);
}
@Override
byte[] toCompactByteArray() {
final boolean srcMemIsCompact = extractCompactFlag(mem);
final int totBytes = getCompactSerializationBytes();
final byte[] byteArr = new byte[totBytes];
final WritableMemory memOut = WritableMemory.writableWrap(byteArr);
if (srcMemIsCompact) { //mem is already consistent with result
mem.copyTo(0, memOut, 0, totBytes);
return byteArr;
}
//everything but the aux array is consistent
mem.copyTo(0, memOut, 0, auxStart);
if (auxHashMap != null) {
final int auxCount = auxHashMap.getAuxCount();
insertAuxCount(memOut, auxCount);
insertLgArr(memOut, auxHashMap.getLgAuxArrInts()); //only used for direct HLL
final PairIterator itr = auxHashMap.getIterator();
int cnt = 0;
while (itr.nextValid()) { //works whether src has compact memory or not
insertInt(memOut, auxStart + (cnt++ << 2), itr.getPair());
}
assert cnt == auxCount;
}
insertCompactFlag(memOut, true);
return byteArr;
}
@Override
byte[] toUpdatableByteArray() {
final boolean memIsCompact = extractCompactFlag(mem);
final int totBytes = getUpdatableSerializationBytes();
final byte[] byteArr = new byte[totBytes];
final WritableMemory memOut = WritableMemory.writableWrap(byteArr);
if (!memIsCompact) { //both mem and target are updatable
mem.copyTo(0, memOut, 0, totBytes);
return byteArr;
}
//mem is compact, need to handle auxArr. Easiest way:
final HllSketch heapSk = HllSketch.heapify(mem);
return heapSk.toUpdatableByteArray();
}
//ITERATOR
final class DirectHll4Iterator extends HllPairIterator {
DirectHll4Iterator(final int lengthPairs) {
super(lengthPairs);
}
@Override
int value() {
return getSlotValue(index);
}
}
}