| /* |
| * 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.kll; |
| |
| import static org.apache.datasketches.common.ByteArrayUtil.copyBytes; |
| import static org.apache.datasketches.kll.KllPreambleUtil.DATA_START_ADR; |
| import static org.apache.datasketches.kll.KllPreambleUtil.DATA_START_ADR_SINGLE_ITEM; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryK; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryLevelZeroSortedFlag; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryM; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryMinK; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryN; |
| import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryNumLevels; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryFamilyID; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryK; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryLevelZeroSortedFlag; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryM; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryMinK; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryN; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryNumLevels; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemoryPreInts; |
| import static org.apache.datasketches.kll.KllPreambleUtil.setMemorySerVer; |
| import static org.apache.datasketches.kll.KllSketch.SketchStructure.COMPACT_EMPTY; |
| import static org.apache.datasketches.kll.KllSketch.SketchStructure.COMPACT_FULL; |
| import static org.apache.datasketches.kll.KllSketch.SketchStructure.COMPACT_SINGLE; |
| import static org.apache.datasketches.kll.KllSketch.SketchStructure.UPDATABLE; |
| import static org.apache.datasketches.kll.KllSketch.SketchType.FLOATS_SKETCH; |
| |
| import org.apache.datasketches.common.ByteArrayUtil; |
| import org.apache.datasketches.common.Family; |
| import org.apache.datasketches.common.SketchesArgumentException; |
| import org.apache.datasketches.memory.Memory; |
| import org.apache.datasketches.memory.MemoryRequestServer; |
| import org.apache.datasketches.memory.WritableMemory; |
| |
| /** |
| * This class implements an off-heap, updatable KllFloatsSketch using WritableMemory. |
| * |
| * <p>Please refer to the documentation in the package-info:<br> |
| * {@link org.apache.datasketches.kll}</p> |
| * |
| * @author Lee Rhodes, Kevin Lang |
| */ |
| class KllDirectFloatsSketch extends KllFloatsSketch { |
| private WritableMemory wmem; |
| private MemoryRequestServer memReqSvr; |
| |
| /** |
| * Constructs from Memory or WritableMemory already initialized with a sketch image and validated. |
| * @param wmem the current WritableMemory |
| * @param memReqSvr the given MemoryRequestServer to request a larger WritableMemory |
| * @param memVal the MemoryValadate object |
| */ |
| KllDirectFloatsSketch( |
| final SketchStructure sketchStructure, |
| final WritableMemory wmem, |
| final MemoryRequestServer memReqSvr, |
| final KllMemoryValidate memVal) { |
| super(sketchStructure); |
| this.wmem = wmem; |
| this.memReqSvr = memReqSvr; |
| readOnly = (wmem != null && wmem.isReadOnly()) || sketchStructure != UPDATABLE; |
| levelsArr = memVal.levelsArr; //always converted to writable form. |
| } |
| |
| /** |
| * Create a new updatable, direct instance of this sketch. |
| * @param k parameter that controls size of the sketch and accuracy of estimates |
| * @param m parameter that controls the minimum level width in items. |
| * @param dstMem the given destination WritableMemory object for use by the sketch |
| * @param memReqSvr the given MemoryRequestServer to request a larger WritableMemory |
| * @return a new instance of this sketch |
| */ |
| static KllDirectFloatsSketch newDirectUpdatableInstance( |
| final int k, |
| final int m, |
| final WritableMemory dstMem, |
| final MemoryRequestServer memReqSvr) { |
| setMemoryPreInts(dstMem, UPDATABLE.getPreInts()); |
| setMemorySerVer(dstMem, UPDATABLE.getSerVer()); |
| setMemoryFamilyID(dstMem, Family.KLL.getID()); |
| setMemoryK(dstMem, k); |
| setMemoryM(dstMem, m); |
| setMemoryN(dstMem, 0); |
| setMemoryMinK(dstMem, k); |
| setMemoryNumLevels(dstMem, 1); |
| int offset = DATA_START_ADR; |
| //new Levels array |
| dstMem.putIntArray(offset, new int[] {k, k}, 0, 2); |
| offset += 2 * Integer.BYTES; |
| //new min/max array |
| dstMem.putFloatArray(offset, new float[] {Float.NaN, Float.NaN}, 0, 2); |
| offset += 2 * ITEM_BYTES; |
| //new empty items array |
| dstMem.putFloatArray(offset, new float[k], 0, k); |
| |
| final KllMemoryValidate memVal = new KllMemoryValidate(dstMem, FLOATS_SKETCH, null); |
| final WritableMemory wMem = dstMem; |
| return new KllDirectFloatsSketch(UPDATABLE, wMem, memReqSvr, memVal); |
| } |
| |
| //End of Constructors |
| |
| @Override |
| String getItemAsString(final int index) { |
| if (isEmpty()) { return "NaN"; } |
| return Float.toString(getFloatItemsArray()[index]); |
| } |
| |
| @Override |
| public int getK() { |
| return getMemoryK(wmem); |
| } |
| |
| //MinMax Methods |
| |
| @Override |
| public float getMaxItem() { |
| if (sketchStructure == COMPACT_EMPTY || isEmpty()) { throw new SketchesArgumentException(EMPTY_MSG); } |
| if (sketchStructure == COMPACT_SINGLE) { return getFloatSingleItem(); } |
| //either compact-full or updatable |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + ITEM_BYTES; |
| return wmem.getFloat(offset); |
| } |
| |
| @Override |
| float getMaxItemInternal() { |
| if (sketchStructure == COMPACT_EMPTY || isEmpty()) { return Float.NaN; } |
| if (sketchStructure == COMPACT_SINGLE) { return getFloatSingleItem(); } |
| //either compact-full or updatable |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + ITEM_BYTES; |
| return wmem.getFloat(offset); |
| } |
| |
| @Override |
| String getMaxItemAsString() { |
| final float maxItem = getMaxItemInternal(); |
| return Float.toString(maxItem); |
| } |
| |
| @Override |
| public float getMinItem() { |
| if (sketchStructure == COMPACT_EMPTY || isEmpty()) { throw new SketchesArgumentException(EMPTY_MSG); } |
| if (sketchStructure == COMPACT_SINGLE) { return getFloatSingleItem(); } |
| //either compact-full or updatable |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure); |
| return wmem.getFloat(offset); |
| } |
| |
| @Override |
| float getMinItemInternal() { |
| if (sketchStructure == COMPACT_EMPTY || isEmpty()) { return Float.NaN; } |
| if (sketchStructure == COMPACT_SINGLE) { return getFloatSingleItem(); } |
| //either compact-full or updatable |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure); |
| return wmem.getFloat(offset); |
| } |
| |
| @Override |
| String getMinItemAsString() { |
| final float minItem = getMinItemInternal(); |
| return Float.toString(minItem); |
| } |
| |
| @Override |
| void setMaxItem(final float item) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + ITEM_BYTES; |
| wmem.putFloat(offset, item); |
| } |
| |
| @Override |
| void setMinItem(final float item) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure); |
| wmem.putFloat(offset, item); |
| } |
| |
| //END MinMax Methods |
| |
| @Override |
| public long getN() { |
| if (sketchStructure == COMPACT_EMPTY) { return 0; } |
| else if (sketchStructure == COMPACT_SINGLE) { return 1; } |
| else { return getMemoryN(wmem); } |
| } |
| |
| //other restricted |
| |
| @Override //returns updatable, expanded array including free space at bottom |
| float[] getFloatItemsArray() { |
| final int k = getK(); |
| if (sketchStructure == COMPACT_EMPTY) { return new float[k]; } |
| if (sketchStructure == COMPACT_SINGLE) { |
| final float[] itemsArr = new float[k]; |
| itemsArr[k - 1] = getFloatSingleItem(); |
| return itemsArr; |
| } |
| final int capacityItems = KllHelper.computeTotalItemCapacity(k, getM(), getNumLevels()); |
| final float[] floatItemsArr = new float[capacityItems]; |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + 2 * ITEM_BYTES; |
| final int shift = (sketchStructure == COMPACT_FULL) ? levelsArr[0] : 0; |
| final int numItems = (sketchStructure == COMPACT_FULL) ? getNumRetained() : capacityItems; |
| wmem.getFloatArray(offset, floatItemsArr, shift, numItems); |
| return floatItemsArr; |
| } |
| |
| @Override //returns compact items array of retained items, no free space. |
| float[] getFloatRetainedItemsArray() { |
| if (sketchStructure == COMPACT_EMPTY) { return new float[0]; } |
| if (sketchStructure == COMPACT_SINGLE) { return new float[] { getFloatSingleItem() }; } |
| final int numRetained = getNumRetained(); |
| final float[] floatItemsArr = new float[numRetained]; |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + 2 * ITEM_BYTES |
| + (sketchStructure == COMPACT_FULL ? 0 : levelsArr[0] * ITEM_BYTES); |
| wmem.getFloatArray(offset, floatItemsArr, 0, numRetained); |
| return floatItemsArr; |
| } |
| |
| @Override |
| float getFloatSingleItem() { |
| if (!isSingleItem()) { throw new SketchesArgumentException(NOT_SINGLE_ITEM_MSG); } |
| if (sketchStructure == COMPACT_SINGLE) { |
| return wmem.getFloat(DATA_START_ADR_SINGLE_ITEM); |
| } |
| final int offset; |
| if (sketchStructure == COMPACT_FULL) { |
| offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + 2 * ITEM_BYTES; |
| } else { //sketchStructure == UPDATABLE |
| offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + (2 + getK() - 1) * ITEM_BYTES; |
| } |
| return wmem.getFloat(offset); |
| } |
| |
| @Override |
| int getM() { |
| return getMemoryM(wmem); |
| } |
| |
| @Override |
| MemoryRequestServer getMemoryRequestServer() { return memReqSvr; } |
| |
| @Override |
| int getMinK() { |
| if (sketchStructure == COMPACT_FULL || sketchStructure == UPDATABLE) { return getMemoryMinK(wmem); } |
| return getK(); |
| } |
| |
| @Override |
| byte[] getMinMaxByteArr() { |
| final byte[] bytesOut = new byte[2 * ITEM_BYTES]; |
| if (sketchStructure == COMPACT_EMPTY) { |
| ByteArrayUtil.putFloatLE(bytesOut, 0, Float.NaN); |
| ByteArrayUtil.putFloatLE(bytesOut, ITEM_BYTES, Float.NaN); |
| return bytesOut; |
| } |
| final int offset; |
| if (sketchStructure == COMPACT_SINGLE) { |
| offset = DATA_START_ADR_SINGLE_ITEM; |
| wmem.getByteArray(offset, bytesOut, 0, ITEM_BYTES); |
| copyBytes(bytesOut, 0, bytesOut, ITEM_BYTES, ITEM_BYTES); |
| return bytesOut; |
| } |
| //sketchStructure == UPDATABLE OR COMPACT_FULL |
| offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure); |
| wmem.getByteArray(offset, bytesOut, 0, ITEM_BYTES); |
| wmem.getByteArray(offset + ITEM_BYTES, bytesOut, ITEM_BYTES, ITEM_BYTES); |
| return bytesOut; |
| } |
| |
| @Override |
| byte[] getRetainedItemsByteArr() { |
| if (sketchStructure == COMPACT_EMPTY) { return new byte[0]; } |
| final float[] fltArr = getFloatRetainedItemsArray(); |
| final byte[] fltByteArr = new byte[fltArr.length * ITEM_BYTES]; |
| final WritableMemory wmem2 = WritableMemory.writableWrap(fltByteArr); |
| wmem2.putFloatArray(0, fltArr, 0, fltArr.length); |
| return fltByteArr; |
| } |
| |
| @Override |
| byte[] getTotalItemsByteArr() { |
| final float[] fltArr = getFloatItemsArray(); |
| final byte[] fltByteArr = new byte[fltArr.length * ITEM_BYTES]; |
| final WritableMemory wmem2 = WritableMemory.writableWrap(fltByteArr); |
| wmem2.putFloatArray(0, fltArr, 0, fltArr.length); |
| return fltByteArr; |
| } |
| |
| @Override |
| WritableMemory getWritableMemory() { |
| return wmem; |
| } |
| |
| @Override |
| void incN(final int increment) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| setMemoryN(wmem, getMemoryN(wmem) + increment); |
| } |
| |
| @Override |
| void incNumLevels() { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| int numLevels = getMemoryNumLevels(wmem); |
| setMemoryNumLevels(wmem, ++numLevels); |
| } |
| |
| @Override |
| boolean isLevelZeroSorted() { |
| return getMemoryLevelZeroSortedFlag(wmem); |
| } |
| |
| @Override |
| void setFloatItemsArray(final float[] floatItems) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + 2 * ITEM_BYTES; |
| wmem.putFloatArray(offset, floatItems, 0, floatItems.length); |
| } |
| |
| @Override |
| void setFloatItemsArrayAt(final int index, final float item) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| final int offset = |
| DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + (index + 2) * ITEM_BYTES; |
| wmem.putFloat(offset, item); |
| } |
| |
| @Override |
| void setFloatItemsArrayAt(final int index, final float[] items, final int srcOffset, final int length) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| final int offset = DATA_START_ADR + getLevelsArrSizeBytes(sketchStructure) + (index + 2) * ITEM_BYTES; |
| wmem.putFloatArray(offset, items, srcOffset, length); |
| } |
| |
| @Override |
| void setLevelZeroSorted(final boolean sorted) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| setMemoryLevelZeroSortedFlag(wmem, sorted); |
| } |
| |
| @Override |
| void setMinK(final int minK) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| setMemoryMinK(wmem, minK); |
| } |
| |
| @Override |
| void setN(final long n) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| setMemoryN(wmem, n); |
| } |
| |
| @Override |
| void setNumLevels(final int numLevels) { |
| if (readOnly) { throw new SketchesArgumentException(TGT_IS_READ_ONLY_MSG); } |
| setMemoryNumLevels(wmem, numLevels); |
| } |
| |
| @Override |
| void setWritableMemory(final WritableMemory wmem) { |
| this.wmem = wmem; |
| } |
| |
| final static class KllDirectCompactFloatsSketch extends KllDirectFloatsSketch { |
| |
| KllDirectCompactFloatsSketch( |
| final SketchStructure sketchStructure, |
| final Memory srcMem, |
| final KllMemoryValidate memVal) { |
| super(sketchStructure, (WritableMemory) srcMem, null, memVal); |
| } |
| } |
| |
| } |