package org.apache.solr.search.field;
/*
* 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.
*/
import org.apache.lucene.util.PagedBytes;
import org.apache.lucene.util.packed.PackedInts;
import java.io.IOException;
public class MonotonicLongArray extends LongArray {
private final LongArray adjustments;
private final long scaled_average_length;
private final int offset; //offset to the adjustment
public static long scaleLength(double averageLength) {
long ret = (long) (averageLength * (1<<24)); // scaled by 1<<24 and then rounded down
assert ret > averageLength; // make sure no overflow
return ret;
}
public MonotonicLongArray(LongArray adjustments, long scaled_average_length, int offset) {
this.adjustments = adjustments;
this.scaled_average_length = scaled_average_length;
this.offset = offset;
}
@Override
public long getSize() {
return adjustments.getSize();
}
@Override
public long getLong(int idx) {
int adjustment = adjustments.getInt(idx) + offset;
return ((scaled_average_length * idx) >>> 24) + adjustment;
}
@Override
public int getInt(int idx) {
return (int)getLong(idx);
}
@Override
public void setLong(int idx, long value) {
long unadjusted = (scaled_average_length * idx) >>> 24;
int diff = (int)(value - unadjusted);
int adjustment = diff - offset;
adjustments.setLong(idx, adjustment);
}
@Override
public long memSize() {
return adjustments.memSize();
}
@Override
public void close() throws IOException {
adjustments.close();
}
public static class Tracker {
long numValues;
long scaled_average_length;
int min_diff = Integer.MAX_VALUE;
int max_diff = Integer.MIN_VALUE;
public Tracker(long numValues, long maxValue) {
this.numValues = numValues;
double averageLength = ((double)maxValue) / numValues;
scaled_average_length = (long) (averageLength * (1<<24)); // scaled by 1<<24 and then rounded down
}
public void add(int idx, long value) {
long unadjusted = (scaled_average_length * idx) >>> 24;
int diff = (int)(value - unadjusted);
if (diff < min_diff) {
min_diff = diff;
}
if (diff > max_diff) {
max_diff = diff;
}
}
public int getRequiredBits() {
return PackedInts.bitsRequired((long)max_diff - min_diff);
}
public int getMinDiff() {
return min_diff;
}
public int getMaxDiff() {
return max_diff;
}
public LongArray createArray() {
int bitsRequired = getRequiredBits();
LongArray adjustments = LongArray.create(numValues, bitsRequired);
int offset;
if (bitsRequired <= 8) {
offset = (int)((1<<7) + min_diff);
} else if (bitsRequired <= 16) {
offset = (int)((1<<15) + min_diff);
} else {
return adjustments; // use the array directly for 32/64 bit
}
MonotonicLongArray arr = new MonotonicLongArray(adjustments, scaled_average_length, offset);
return arr;
}
}
}