| /* |
| * 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(); |
| } |
| |
| } |