blob: 1b6489b2871c2f9ca5c68a354270eb39b47ec5d0 [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.quantiles;
import java.util.Arrays;
import java.util.Comparator;
final class ItemsUpdateImpl {
private ItemsUpdateImpl() {}
//important: newN might not equal n_
// This only increases the size and does not touch or move any data.
static <T> void maybeGrowLevels(final ItemsSketch<T> sketch, final long newN) {
// important: newN might not equal n_
final int k = sketch.getK();
final int numLevelsNeeded = Util.computeNumLevelsNeeded(k, newN);
if (numLevelsNeeded == 0) {
// don't need any levels yet, and might have small base buffer; this can happen during a merge
return;
}
// from here on we need a full-size base buffer and at least one level
assert newN >= 2L * k;
assert numLevelsNeeded > 0;
final int spaceNeeded = (2 + numLevelsNeeded) * k;
if (spaceNeeded <= sketch.getCombinedBufferAllocatedCount()) {
return;
}
// copies base buffer plus old levels
sketch.combinedBuffer_ = Arrays.copyOf(sketch.getCombinedBuffer(), spaceNeeded);
sketch.combinedBufferItemCapacity_ = spaceNeeded;
}
@SuppressWarnings("unchecked")
static <T> void inPlacePropagateCarry(
final int startingLevel,
final T[] sizeKBuf, final int sizeKStart,
final T[] size2KBuf, final int size2KStart,
final boolean doUpdateVersion,
final ItemsSketch<T> sketch) { // else doMergeIntoVersion
final Object[] levelsArr = sketch.getCombinedBuffer();
final long bitPattern = sketch.getBitPattern();
final int k = sketch.getK();
final int endingLevel = Util.lowestZeroBitStartingAt(bitPattern, startingLevel);
if (doUpdateVersion) { // update version of computation
// its is okay for sizeKbuf to be null in this case
zipSize2KBuffer(
size2KBuf, size2KStart,
levelsArr, (2 + endingLevel) * k,
k);
} else { // mergeInto version of computation
System.arraycopy(
sizeKBuf, sizeKStart,
levelsArr, (2 + endingLevel) * k,
k);
}
for (int lvl = startingLevel; lvl < endingLevel; lvl++) {
assert (bitPattern & (1L << lvl)) > 0; // internal consistency check
mergeTwoSizeKBuffers(
(T[]) levelsArr, (2 + lvl) * k,
(T[]) levelsArr, (2 + endingLevel) * k,
size2KBuf, size2KStart,
k, sketch.getComparator());
zipSize2KBuffer(
size2KBuf, size2KStart,
levelsArr, (2 + endingLevel) * k,
k);
// to release the discarded objects
Arrays.fill(levelsArr, (2 + lvl) * k, (2 + lvl + 1) * k, null);
} // end of loop over lower levels
// update bit pattern with binary-arithmetic ripple carry
sketch.bitPattern_ = bitPattern + (1L << startingLevel);
}
//note: this version refers to the ItemsSketch.rand
private static void zipSize2KBuffer(
final Object[] bufA, final int startA, // input
final Object[] bufC, final int startC, // output
final int k) {
final int randomOffset = ItemsSketch.rand.nextBoolean() ? 1 : 0;
final int limC = startC + k;
for (int a = startA + randomOffset, c = startC; c < limC; a += 2, c++) {
bufC[c] = bufA[a];
}
}
//note: this version uses a comparator
private static <T> void mergeTwoSizeKBuffers(
final T[] keySrc1, final int arrStart1,
final T[] keySrc2, final int arrStart2,
final T[] keyDst, final int arrStart3,
final int k, final Comparator<? super T> comparator) {
final int arrStop1 = arrStart1 + k;
final int arrStop2 = arrStart2 + k;
int i1 = arrStart1;
int i2 = arrStart2;
int i3 = arrStart3;
while (i1 < arrStop1 && i2 < arrStop2) {
if (comparator.compare(keySrc2[i2], keySrc1[i1]) < 0) {
keyDst[i3++] = keySrc2[i2++];
} else {
keyDst[i3++] = keySrc1[i1++];
}
}
if (i1 < arrStop1) {
System.arraycopy(keySrc1, i1, keyDst, i3, arrStop1 - i1);
} else {
assert i2 < arrStop2;
System.arraycopy(keySrc1, i2, keyDst, i3, arrStop2 - i2);
}
}
}