blob: 37fabf844e7fb919e169a20ae06c940365697d38 [file]
/*
* 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.theta;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_FLOAT_UNALIGNED;
import static java.lang.foreign.ValueLayout.JAVA_INT_UNALIGNED;
import static java.lang.foreign.ValueLayout.JAVA_LONG_UNALIGNED;
import static org.apache.datasketches.theta.CompactOperations.checkIllegalCurCountAndEmpty;
import static org.apache.datasketches.theta.CompactOperations.computeCompactPreLongs;
import static org.apache.datasketches.theta.CompactOperations.correctThetaOnCompact;
import static org.apache.datasketches.theta.PreambleUtil.FAMILY_BYTE;
import static org.apache.datasketches.theta.PreambleUtil.LG_ARR_LONGS_BYTE;
import static org.apache.datasketches.theta.PreambleUtil.LG_RESIZE_FACTOR_BIT;
import static org.apache.datasketches.theta.PreambleUtil.PREAMBLE_LONGS_BYTE;
import static org.apache.datasketches.theta.PreambleUtil.P_FLOAT;
import static org.apache.datasketches.theta.PreambleUtil.RETAINED_ENTRIES_INT;
import static org.apache.datasketches.theta.PreambleUtil.THETA_LONG;
import static org.apache.datasketches.theta.PreambleUtil.checkSegPreambleCap;
import static org.apache.datasketches.theta.PreambleUtil.extractCurCount;
import static org.apache.datasketches.theta.PreambleUtil.extractLgArrLongs;
import static org.apache.datasketches.theta.PreambleUtil.extractLgNomLongs;
import static org.apache.datasketches.theta.PreambleUtil.extractThetaLong;
import static org.apache.datasketches.theta.PreambleUtil.insertThetaLong;
import java.lang.foreign.MemorySegment;
import java.util.Objects;
import org.apache.datasketches.common.Family;
import org.apache.datasketches.common.MemorySegmentStatus;
import org.apache.datasketches.common.ResizeFactor;
import org.apache.datasketches.common.SketchesReadOnlyException;
/**
* The read-only ThetaSketch in a MemorySegment.
*
* <p>This implementation uses data in a given MemorySegment that is owned and managed by the caller.
* This MemorySegment can be off-heap, which if managed properly will greatly reduce the need for
* the JVM to perform garbage collection.</p>
*
* @author Lee Rhodes
* @author Kevin Lang
*/
class DirectQuickSelectSketchR extends UpdatableThetaSketch {
/**
* This MemorySegment reference is also used by the writable child DirectQuickSelectThetaSketch.
*
* <p>When this class is constructed with the writable constructor, called by the writable child DirectQuickSelectThetaSketch,
* this reference can be changed, its contents can be modified.</p>
*
* <p>When this class is constructed with the read-only constructor, called from local factories, this MemorySegment will
* be placed in read-only mode.</p>
*/
MemorySegment wseg_; //
/**
* This writable constructor is only called by the writable child DirectQuickSelectThetaSketch and then this class provides the
* read-only methods for the DirectQuickSelectThetaSketch class.
* @param wseg the writable MemorySegment used by the writable child DirectQuickSelectThetaSketch.
* @param seed the seed for the update function for the writable child DirectQuickSelectThetaSketch.
*/
DirectQuickSelectSketchR(final MemorySegment wseg, final long seed) {
Objects.requireNonNull(wseg, "MemorySegment wseg must not be null");
super(seed);
wseg_ = wseg;
}
/**
* This read-only constructor is only called by local factory methods which use this class as a read-only direct sketch.
* @param seed the seed used to validate the internal hashes of the given source MemorySegment.
* @param srcSeg the read-only MemorySegment used by this class in read-only mode.
*/
private DirectQuickSelectSketchR(final long seed, final MemorySegment srcSeg) {
Objects.requireNonNull(srcSeg, "MemorySegment srcSeg must not be null");
super(seed);
wseg_ = srcSeg.asReadOnly();
}
/**
* Wrap a sketch around the given source MemorySegment containing sketch data that originated from this sketch.
* @param srcSeg the source MemorySegment.
* The given MemorySegment object must be in hash table form and not read only.
* @param seed <a href="{@docRoot}/resources/dictionary.html#seed">See Update Hash Seed</a>
* @return instance of this sketch
*/
static DirectQuickSelectSketchR readOnlyWrap(final MemorySegment srcSeg, final long seed) {
final int preambleLongs = checkSegPreambleCap(srcSeg); //byte 0
final int lgNomLongs = extractLgNomLongs(srcSeg); //byte 3
final int lgArrLongs = extractLgArrLongs(srcSeg); //byte 4
checkSegIntegrity(srcSeg, seed, preambleLongs, lgNomLongs, lgArrLongs);
UpdatableThetaSketch.checkUnionAndQuickSelectFamily(srcSeg, preambleLongs, lgNomLongs);
return new DirectQuickSelectSketchR(seed, srcSeg);
}
/**
* Fast-wrap a sketch around the given source MemorySegment containing sketch data that originated from
* this sketch. This does NO validity checking of the given MemorySegment.
* Caller must ensure segment contents are a valid sketch image.
* @param srcSeg The given MemorySegment object must be in hash table form and not read only.
* @param seed <a href="{@docRoot}/resources/dictionary.html#seed">See Update Hash Seed</a>
* @return instance of this sketch
*/
static DirectQuickSelectSketchR fastReadOnlyWrap(final MemorySegment srcSeg, final long seed) {
return new DirectQuickSelectSketchR(seed, srcSeg);
}
//ThetaSketch
@Override
public int getCurrentBytes() {
//not compact
final int lgArrLongs = wseg_.get(JAVA_BYTE, LG_ARR_LONGS_BYTE) & 0XFF; //mask to byte
final int preLongs = wseg_.get(JAVA_BYTE, PREAMBLE_LONGS_BYTE) & 0X3F; //mask to 6 bits
return preLongs + (1 << lgArrLongs) << 3;
}
@Override
public double getEstimate() {
final int curCount = extractCurCount(wseg_);
final long thetaLong = extractThetaLong(wseg_);
return ThetaSketch.estimate(thetaLong, curCount);
}
@Override
public Family getFamily() {
final int familyID = wseg_.get(JAVA_BYTE, FAMILY_BYTE) & 0XFF; //mask to byte
return Family.idToFamily(familyID);
}
@Override
public int getRetainedEntries(final boolean valid) { //valid is only relevant for the AlphaSketch
return wseg_.get(JAVA_INT_UNALIGNED, RETAINED_ENTRIES_INT);
}
@Override
public long getThetaLong() {
return isEmpty() ? Long.MAX_VALUE : wseg_.get(JAVA_LONG_UNALIGNED, THETA_LONG);
}
@Override
public boolean hasMemorySegment() {
return wseg_ != null && wseg_.scope().isAlive();
}
@Override
public boolean isOffHeap() {
return hasMemorySegment() && wseg_.isNative();
}
@Override
public boolean isEmpty() {
return PreambleUtil.isEmptyFlag(wseg_);
}
@Override
public boolean isSameResource(final MemorySegment that) {
return hasMemorySegment() && MemorySegmentStatus.isSameResource(wseg_, that); //null checks done here
}
@Override
public HashIterator iterator() {
return new MemorySegmentHashIterator(wseg_, 1 << getLgArrLongs(), getThetaLong());
}
@Override
public byte[] toByteArray() { //MY_FAMILY is stored in wseg_
final int curCount = extractCurCount(wseg_);
checkIllegalCurCountAndEmpty(isEmpty(), curCount);
final int lengthBytes = getCurrentBytes();
final byte[] byteArray = new byte[lengthBytes];
final MemorySegment seg = MemorySegment.ofArray(byteArray);
MemorySegment.copy(wseg_, 0, seg, 0, lengthBytes);
final long thetaLong = correctThetaOnCompact(isEmpty(), curCount, extractThetaLong(wseg_));
insertThetaLong(seg, thetaLong);
return byteArray;
}
//UpdatableThetaSketch
@Override
public final int getLgNomLongs() {
return PreambleUtil.extractLgNomLongs(wseg_);
}
@Override
float getP() {
return wseg_.get(JAVA_FLOAT_UNALIGNED, P_FLOAT);
}
@Override
public ResizeFactor getResizeFactor() {
return ResizeFactor.getRF(getLgRF());
}
@Override
public UpdatableThetaSketch rebuild() {
throw new SketchesReadOnlyException();
}
@Override
public void reset() {
throw new SketchesReadOnlyException();
}
//restricted methods
@Override
long[] getCache() {
final long lgArrLongs = wseg_.get(JAVA_BYTE, LG_ARR_LONGS_BYTE) & 0XFF; //mask to byte
final int preambleLongs = wseg_.get(JAVA_BYTE, PREAMBLE_LONGS_BYTE) & 0X3F; //mask to 6 bits
final long[] cacheArr = new long[1 << lgArrLongs];
MemorySegment.copy(wseg_, JAVA_LONG_UNALIGNED, preambleLongs << 3, cacheArr, 0, 1 << lgArrLongs);
return cacheArr;
}
@Override
int getCompactPreambleLongs() {
return computeCompactPreLongs(isEmpty(), getRetainedEntries(true), getThetaLong());
}
@Override
int getCurrentPreambleLongs() {
return ThetaSketch.getPreambleLongs(wseg_);
}
@Override
MemorySegment getMemorySegment() {
return wseg_;
}
@Override
short getSeedHash() {
return (short) PreambleUtil.extractSeedHash(wseg_);
}
@Override
boolean isDirty() {
return false; //Always false for QuickSelectThetaSketch
}
@Override
boolean isOutOfSpace(final int numEntries) { //overridden by writable DirectQuickSelectSketch
return false;
}
@Override
int getLgArrLongs() {
return wseg_.get(JAVA_BYTE, LG_ARR_LONGS_BYTE) & 0XFF; //mask to byte
}
int getLgRF() { //only Direct needs this
return wseg_.get(JAVA_BYTE, PREAMBLE_LONGS_BYTE) >>> LG_RESIZE_FACTOR_BIT & 0X3; //mask to 2 bits
}
@Override
UpdateReturnState hashUpdate(final long hash) {
throw new SketchesReadOnlyException();
}
}