blob: 1588112a6bb802fba000fca68375ca2cd57ef99b [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.kll;
import static org.apache.datasketches.Family.idToFamily;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.EMPTYBIT_AND_PREINTS;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.EMPTYBIT_AND_SER_VER;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.EMPTYBIT_AND_SINGLEBIT;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.INVALID_PREINTS;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.SINGLEBIT_AND_PREINTS;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.SINGLEBIT_AND_SER_VER;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.SRC_NOT_KLL;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.UPDATABLEBIT_AND_SER_VER;
import static org.apache.datasketches.kll.KllMemoryValidate.MemoryInputError.memoryValidateThrow;
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.PREAMBLE_INTS_EMPTY_SINGLE;
import static org.apache.datasketches.kll.KllPreambleUtil.PREAMBLE_INTS_FULL;
import static org.apache.datasketches.kll.KllPreambleUtil.SERIAL_VERSION_EMPTY_FULL;
import static org.apache.datasketches.kll.KllPreambleUtil.SERIAL_VERSION_SINGLE;
import static org.apache.datasketches.kll.KllPreambleUtil.SERIAL_VERSION_UPDATABLE;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryDoubleSketchFlag;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryEmptyFlag;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryFamilyID;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryFlags;
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.getMemoryPreInts;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemorySerVer;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemorySingleItemFlag;
import static org.apache.datasketches.kll.KllPreambleUtil.getMemoryUpdatableFormatFlag;
import org.apache.datasketches.Family;
import org.apache.datasketches.SketchesArgumentException;
import org.apache.datasketches.memory.Memory;
import org.apache.datasketches.memory.WritableMemory;
/**
* This class performs all the error checking of an incoming Memory object and extracts the key fields in the process.
* This is used by all sketches that read or import Memory objects.
*
* @author lrhodes
*
*/
final class KllMemoryValidate {
// first 8 bytes
final int preInts; // = extractPreInts(srcMem);
final int serVer;
final int familyID;
final String famName;
final int flags;
boolean empty;
boolean singleItem;
final boolean level0Sorted;
final boolean doublesSketch;
final boolean updatableMemFormat;
final boolean readOnly;
final int k;
final int m;
final int typeBytes;
// depending on the layout, the next 8-16 bytes of the preamble, may be filled with assumed values.
// For example, if the layout is compact & empty, n = 0, if compact and single, n = 1, etc.
long n;
// next 4 bytes
int minK;
int numLevels;
// derived
int sketchBytes;
int[] levelsArr; //adjusted to include top index
KllMemoryValidate(final Memory srcMem) {
readOnly = srcMem.isReadOnly();
preInts = getMemoryPreInts(srcMem);
serVer = getMemorySerVer(srcMem);
familyID = getMemoryFamilyID(srcMem);
if (familyID != Family.KLL.getID()) { memoryValidateThrow(SRC_NOT_KLL, familyID); }
famName = idToFamily(familyID).toString();
flags = getMemoryFlags(srcMem);
updatableMemFormat = getMemoryUpdatableFormatFlag(srcMem);
empty = getMemoryEmptyFlag(srcMem);
singleItem = getMemorySingleItemFlag(srcMem);
level0Sorted = getMemoryLevelZeroSortedFlag(srcMem);
doublesSketch = getMemoryDoubleSketchFlag(srcMem);
k = getMemoryK(srcMem);
m = getMemoryM(srcMem);
KllHelper.checkM(m);
KllHelper.checkK(k, m);
if ((serVer == SERIAL_VERSION_UPDATABLE) ^ updatableMemFormat) { memoryValidateThrow(UPDATABLEBIT_AND_SER_VER, 1); }
typeBytes = doublesSketch ? Double.BYTES : Float.BYTES;
if (updatableMemFormat) { updatableMemFormatValidate((WritableMemory) srcMem); }
else { compactMemoryValidate(srcMem); }
}
void compactMemoryValidate(final Memory srcMem) { //FOR HEAPIFY
if (empty && singleItem) { memoryValidateThrow(EMPTYBIT_AND_SINGLEBIT, flags); }
final int sw = (empty ? 1 : 0) | (singleItem ? 4 : 0);
switch (sw) {
case 0: { //FULL_COMPACT
if (preInts != PREAMBLE_INTS_FULL) { memoryValidateThrow(INVALID_PREINTS, preInts); }
if (serVer != SERIAL_VERSION_EMPTY_FULL) { memoryValidateThrow(EMPTYBIT_AND_SER_VER, serVer); }
n = getMemoryN(srcMem);
minK = getMemoryMinK(srcMem);
numLevels = getMemoryNumLevels(srcMem);
// Create Levels Arr
levelsArr = new int[numLevels + 1];
srcMem.getIntArray(DATA_START_ADR, levelsArr, 0, numLevels); //copies all except the last one
final int capacityItems = KllHelper.computeTotalItemCapacity(k, m, numLevels);
levelsArr[numLevels] = capacityItems; //load the last one
final int retainedItems = (levelsArr[numLevels] - levelsArr[0]);
sketchBytes = DATA_START_ADR + numLevels * Integer.BYTES + 2 * typeBytes + retainedItems * typeBytes;
break;
}
case 1: { //EMPTY_COMPACT
if (preInts != PREAMBLE_INTS_EMPTY_SINGLE) { memoryValidateThrow(EMPTYBIT_AND_PREINTS, preInts); }
if (serVer != SERIAL_VERSION_EMPTY_FULL) { memoryValidateThrow(EMPTYBIT_AND_SER_VER, serVer); }
n = 0; //assumed
minK = k; //assumed
numLevels = 1; //assumed
levelsArr = new int[] {k, k};
sketchBytes = DATA_START_ADR_SINGLE_ITEM;
break;
}
case 4: { //SINGLE_COMPACT
if (preInts != PREAMBLE_INTS_EMPTY_SINGLE) { memoryValidateThrow(SINGLEBIT_AND_PREINTS, preInts); }
if (serVer != SERIAL_VERSION_SINGLE) { memoryValidateThrow(SINGLEBIT_AND_SER_VER, serVer); }
n = 1; //assumed
minK = k; //assumed
numLevels = 1; //assumed
levelsArr = new int[] {k - 1, k};
sketchBytes = DATA_START_ADR_SINGLE_ITEM + typeBytes;
break;
}
default: //can not happen
}
}
void updatableMemFormatValidate(final WritableMemory wSrcMem) {
if (preInts != PREAMBLE_INTS_FULL) { memoryValidateThrow(INVALID_PREINTS, preInts); }
n = getMemoryN(wSrcMem);
empty = n == 0; //empty & singleItem are set for convenience
singleItem = n == 1; // there is no error checking on these bits
minK = getMemoryMinK(wSrcMem);
numLevels = getMemoryNumLevels(wSrcMem);
levelsArr = new int[numLevels + 1];
wSrcMem.getIntArray(DATA_START_ADR, levelsArr, 0, numLevels + 1);
final int capacity = levelsArr[numLevels];
sketchBytes =
DATA_START_ADR + levelsArr.length * Integer.BYTES + 2 * typeBytes + capacity * typeBytes;
}
enum MemoryInputError {
SRC_NOT_KLL("FamilyID Field must be: " + Family.KLL.getID() + ", NOT: "),
EMPTYBIT_AND_PREINTS("Empty Bit: 1 -> PreInts: " + PREAMBLE_INTS_EMPTY_SINGLE + ", NOT: "),
EMPTYBIT_AND_SER_VER("Empty Bit: 1 -> SerVer: " + SERIAL_VERSION_EMPTY_FULL + ", NOT: "),
SINGLEBIT_AND_SER_VER("Single Item Bit: 1 -> SerVer: " + SERIAL_VERSION_SINGLE + ", NOT: "),
SINGLEBIT_AND_PREINTS("Single Item Bit: 1 -> PreInts: " + PREAMBLE_INTS_EMPTY_SINGLE + ", NOT: "),
INVALID_PREINTS("PreInts Must Be: " + PREAMBLE_INTS_FULL + ", NOT: "),
UPDATABLEBIT_AND_SER_VER("((SerVer == 3) ^ (Updatable Bit)) must = 0, NOT: "),
EMPTYBIT_AND_SINGLEBIT("Empty flag bit and SingleItem flag bit cannot both be set. Flags: ");
private String msg;
private MemoryInputError(final String msg) {
this.msg = msg;
}
private String getMessage() {
return msg;
}
final static void memoryValidateThrow(final MemoryInputError errType, final int value) {
throw new SketchesArgumentException(errType.getMessage() + value);
}
}
}