blob: 3e08144fb5d527194240c598ffc0024b2e5c2fc1 [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.AbstractCoupons.find;
import static org.apache.datasketches.hll.HllUtil.LG_AUX_ARR_INTS;
import static org.apache.datasketches.hll.PreambleUtil.AUX_COUNT_INT;
import static org.apache.datasketches.hll.PreambleUtil.HLL_BYTE_ARR_START;
import static org.apache.datasketches.hll.PreambleUtil.insertAuxCount;
import static org.apache.datasketches.hll.PreambleUtil.insertCompactFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertCurMin;
import static org.apache.datasketches.hll.PreambleUtil.insertCurMode;
import static org.apache.datasketches.hll.PreambleUtil.insertEmptyFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertFamilyId;
import static org.apache.datasketches.hll.PreambleUtil.insertHashSetCount;
import static org.apache.datasketches.hll.PreambleUtil.insertHipAccum;
import static org.apache.datasketches.hll.PreambleUtil.insertInt;
import static org.apache.datasketches.hll.PreambleUtil.insertKxQ0;
import static org.apache.datasketches.hll.PreambleUtil.insertKxQ1;
import static org.apache.datasketches.hll.PreambleUtil.insertLgArr;
import static org.apache.datasketches.hll.PreambleUtil.insertLgK;
import static org.apache.datasketches.hll.PreambleUtil.insertListCount;
import static org.apache.datasketches.hll.PreambleUtil.insertNumAtCurMin;
import static org.apache.datasketches.hll.PreambleUtil.insertOooFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertPreInts;
import static org.apache.datasketches.hll.PreambleUtil.insertRebuildCurMinNumKxQFlag;
import static org.apache.datasketches.hll.PreambleUtil.insertSerVer;
import static org.apache.datasketches.hll.PreambleUtil.insertTgtHllType;
import org.apache.datasketches.SketchesStateException;
import org.apache.datasketches.memory.Memory;
import org.apache.datasketches.memory.WritableMemory;
/**
* @author Lee Rhodes
*/
class ToByteArrayImpl {
// To byte array used by the heap HLL modes.
static final byte[] toHllByteArray(final AbstractHllArray impl, final boolean compact) {
int auxBytes = 0;
if (impl.tgtHllType == TgtHllType.HLL_4) {
final AuxHashMap auxHashMap = impl.getAuxHashMap();
if (auxHashMap != null) {
auxBytes = (compact)
? auxHashMap.getCompactSizeBytes()
: auxHashMap.getUpdatableSizeBytes();
} else {
auxBytes = (compact) ? 0 : 4 << LG_AUX_ARR_INTS[impl.lgConfigK];
}
}
final int totBytes = HLL_BYTE_ARR_START + impl.getHllByteArrBytes() + auxBytes;
final byte[] byteArr = new byte[totBytes];
final WritableMemory wmem = WritableMemory.writableWrap(byteArr);
insertHll(impl, wmem, compact);
return byteArr;
}
private static final void insertHll(final AbstractHllArray impl, final WritableMemory wmem,
final boolean compact) {
insertCommonHll(impl, wmem, compact);
final byte[] hllByteArr = ((HllArray)impl).hllByteArr;
wmem.putByteArray(HLL_BYTE_ARR_START, hllByteArr, 0, hllByteArr.length);
if (impl.getAuxHashMap() != null) {
insertAux(impl, wmem, compact);
} else {
wmem.putInt(AUX_COUNT_INT, 0);
}
}
private static final void insertCommonHll(final AbstractHllArray srcImpl,
final WritableMemory tgtWmem, final boolean compact) {
insertPreInts(tgtWmem, srcImpl.getPreInts());
insertSerVer(tgtWmem);
insertFamilyId(tgtWmem);
insertLgK(tgtWmem, srcImpl.getLgConfigK());
insertEmptyFlag(tgtWmem, srcImpl.isEmpty());
insertCompactFlag(tgtWmem, compact);
insertOooFlag(tgtWmem, srcImpl.isOutOfOrder());
insertCurMin(tgtWmem, srcImpl.getCurMin());
insertCurMode(tgtWmem, srcImpl.getCurMode());
insertTgtHllType(tgtWmem, srcImpl.getTgtHllType());
insertHipAccum(tgtWmem, srcImpl.getHipAccum());
insertKxQ0(tgtWmem, srcImpl.getKxQ0());
insertKxQ1(tgtWmem, srcImpl.getKxQ1());
insertNumAtCurMin(tgtWmem, srcImpl.getNumAtCurMin());
insertRebuildCurMinNumKxQFlag(tgtWmem, srcImpl.isRebuildCurMinNumKxQFlag());
}
private static final void insertAux(final AbstractHllArray srcImpl, final WritableMemory tgtWmem,
final boolean tgtCompact) {
final AuxHashMap auxHashMap = srcImpl.getAuxHashMap();
final int auxCount = auxHashMap.getAuxCount();
insertAuxCount(tgtWmem, auxCount);
insertLgArr(tgtWmem, auxHashMap.getLgAuxArrInts()); //only used for direct HLL
final long auxStart = srcImpl.auxStart;
if (tgtCompact) {
final PairIterator itr = auxHashMap.getIterator();
int cnt = 0;
while (itr.nextValid()) { //works whether src has compact memory or not
insertInt(tgtWmem, auxStart + (cnt++ << 2), itr.getPair());
}
assert cnt == auxCount;
} else { //updatable
final int auxInts = 1 << auxHashMap.getLgAuxArrInts();
final int[] auxArr = auxHashMap.getAuxIntArr();
tgtWmem.putIntArray(auxStart, auxArr, 0, auxInts);
}
}
//To byte array for coupons
static final byte[] toCouponByteArray(final AbstractCoupons impl, final boolean dstCompact) {
final int srcCouponCount = impl.getCouponCount();
final int srcLgCouponArrInts = impl.getLgCouponArrInts();
final int srcCouponArrInts = 1 << srcLgCouponArrInts;
final byte[] byteArrOut;
final boolean list = impl.getCurMode() == CurMode.LIST;
//prepare switch
final int sw = (impl.isMemory() ? 0 : 4) | (impl.isCompact() ? 0 : 2) | (dstCompact ? 0 : 1);
switch (sw) {
case 0: { //Src Memory, Src Compact, Dst Compact
final Memory srcMem = impl.getMemory();
final int bytesOut = impl.getMemDataStart() + (srcCouponCount << 2);
byteArrOut = new byte[bytesOut];
srcMem.getByteArray(0, byteArrOut, 0, bytesOut);
break;
}
case 1: { //Src Memory, Src Compact, Dst Updatable
final int dataStart = impl.getMemDataStart();
final int bytesOut = dataStart + (srcCouponArrInts << 2);
byteArrOut = new byte[bytesOut];
final WritableMemory memOut = WritableMemory.writableWrap(byteArrOut);
copyCommonListAndSet(impl, memOut);
insertCompactFlag(memOut, dstCompact);
final int[] tgtCouponIntArr = new int[srcCouponArrInts];
final PairIterator itr = impl.iterator();
while (itr.nextValid()) {
final int pair = itr.getPair();
final int idx = find(tgtCouponIntArr, srcLgCouponArrInts, pair);
if (idx < 0) { //found EMPTY
tgtCouponIntArr[~idx] = pair; //insert
continue;
}
throw new SketchesStateException("Error: found duplicate.");
}
memOut.putIntArray(dataStart, tgtCouponIntArr, 0, srcCouponArrInts);
if (list) {
insertListCount(memOut, srcCouponCount);
} else {
insertHashSetCount(memOut, srcCouponCount);
}
break;
}
case 2: { //Src Memory, Src Updatable, Dst Compact
final int dataStart = impl.getMemDataStart();
final int bytesOut = dataStart + (srcCouponCount << 2);
byteArrOut = new byte[bytesOut];
final WritableMemory memOut = WritableMemory.writableWrap(byteArrOut);
copyCommonListAndSet(impl, memOut);
insertCompactFlag(memOut, dstCompact);
final PairIterator itr = impl.iterator();
int cnt = 0;
while (itr.nextValid()) {
insertInt(memOut, dataStart + (cnt++ << 2), itr.getPair());
}
if (list) {
insertListCount(memOut, srcCouponCount);
} else {
insertHashSetCount(memOut, srcCouponCount);
}
break;
}
case 3: { //Src Memory, Src Updatable, Dst Updatable
final Memory srcMem = impl.getMemory();
final int bytesOut = impl.getMemDataStart() + (srcCouponArrInts << 2);
byteArrOut = new byte[bytesOut];
srcMem.getByteArray(0, byteArrOut, 0, bytesOut);
break;
}
case 6: { //Src Heap, Src Updatable, Dst Compact
final int dataStart = impl.getMemDataStart();
final int bytesOut = dataStart + (srcCouponCount << 2);
byteArrOut = new byte[bytesOut];
final WritableMemory memOut = WritableMemory.writableWrap(byteArrOut);
copyCommonListAndSet(impl, memOut);
insertCompactFlag(memOut, dstCompact);
final PairIterator itr = impl.iterator();
int cnt = 0;
while (itr.nextValid()) {
insertInt(memOut, dataStart + (cnt++ << 2), itr.getPair());
}
if (list) {
insertListCount(memOut, srcCouponCount);
} else {
insertHashSetCount(memOut, srcCouponCount);
}
break;
}
case 7: { //Src Heap, Src Updatable, Dst Updatable
final int dataStart = impl.getMemDataStart();
final int bytesOut = dataStart + (srcCouponArrInts << 2);
byteArrOut = new byte[bytesOut];
final WritableMemory memOut = WritableMemory.writableWrap(byteArrOut);
copyCommonListAndSet(impl, memOut);
memOut.putIntArray(dataStart, impl.getCouponIntArr(), 0, srcCouponArrInts);
if (list) {
insertListCount(memOut, srcCouponCount);
} else {
insertHashSetCount(memOut, srcCouponCount);
}
break;
}
default: throw new SketchesStateException("Corruption, should not happen: " + sw);
}
return byteArrOut;
}
private static final void copyCommonListAndSet(final AbstractCoupons impl,
final WritableMemory wmem) {
insertPreInts(wmem, impl.getPreInts());
insertSerVer(wmem);
insertFamilyId(wmem);
insertLgK(wmem, impl.getLgConfigK());
insertLgArr(wmem, impl.getLgCouponArrInts());
insertEmptyFlag(wmem, impl.isEmpty());
insertOooFlag(wmem, impl.isOutOfOrder());
insertCurMode(wmem, impl.getCurMode());
insertTgtHllType(wmem, impl.getTgtHllType());
}
}