/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.data.types.lng.array;
import java.lang.ref.WeakReference;
import org.apache.thrift.TBase;
/**
* Abstract implementation of {@link ExplorableCompressedLongArray} which handles the {@link State} transitions and
* introduces compression preparation.
*
* @param <T>
* Thrift class this long array can be serialized to/from.
*
* @author Bastian Gloeckle
*/
public abstract class AbstractExplorableCompressedLongArray<T extends TBase<?, ?>>
implements ExplorableCompressedLongArray<T> {
/** {@link State} this instance is in. */
protected State state;
/**
* If not <code>null</code> this is a reference to the array that was {@link #prepareCompression(long[], boolean)}d
* last (i.e. that was used in a call to {@link #expectedCompressionRatio(long[], boolean)} last).
*/
protected WeakReference<long[]> preparedInputArray = null;
public AbstractExplorableCompressedLongArray() {
state = State.EXPLORING;
}
@Override
public double expectedCompressionRatio(long[] inputArray, boolean isSorted) throws IllegalStateException {
if (!State.EXPLORING.equals(state))
throw new IllegalStateException("Not in Exploring state.");
prepareCompression(inputArray, isSorted);
return doExpectedCompressionRatio(inputArray, isSorted);
}
/**
* Calculate an approximation of the compression ratio of the given input array.
*
* This method can safely assume that {@link #doPrepareCompression(long[], boolean)} was called before with the same
* array and the fields of the object that are set by latter method are still in the correct state.
*
* @param inputArray
* See {@link #expectedCompressionRatio(long[], boolean)}
* @param isSorted
* See {@link #expectedCompressionRatio(long[], boolean)}
* @return See {@link #expectedCompressionRatio(long[], boolean)}
*/
abstract protected double doExpectedCompressionRatio(long[] inputArray, boolean isSorted);
@Override
public void compress(long[] inputArray, boolean isSorted) throws IllegalStateException {
if (!State.EXPLORING.equals(state))
throw new IllegalStateException("Not in Exploring state.");
prepareCompression(inputArray, isSorted);
doCompress(inputArray, isSorted);
state = State.COMPRESSED;
}
/**
* Compress the input array.
*
* This method can safely assume that {@link #doPrepareCompression(long[], boolean)} was called before with the same
* array and the fields of the object that are set by latter method are still in the correct state.
*
* @param inputArray
* The input array to compress.
* @param isSorted
* true if the input array is sorted.
*/
abstract protected void doCompress(long[] inputArray, boolean isSorted);
protected void prepareCompression(long[] inputArray, boolean isSorted) {
if (preparedInputArray != null && preparedInputArray.get() == inputArray)
// we prepared the values for this input array already, no need to do it again.
return;
doPrepareCompression(inputArray, isSorted);
preparedInputArray = new WeakReference<long[]>(inputArray);
}
/**
* Prepares the compression by evaluating the input array and calculating any compression-specific statistics from it.
*
* <p>
* This method should prepare all data that is needed for either {@link #doCompress(long[], boolean)} or
* {@link #doExpectedCompressionRatio(long[], boolean)} calculations. This method is guaranteed to be executed before
* those calculation methods are called.
*
* <p>
* This method should not execute the compression itself.
*
* <p>
* It is expected that calling this method will have side-effects on the fields of the object.
*
* @param inputArray
* The array of which the compression-statistics are calculated.
* @param isSorted
* true if the input array is sorted.
*/
abstract protected void doPrepareCompression(long[] inputArray, boolean isSorted);
@Override
public String toString() {
// for debugging we implement the toString method.
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName());
sb.append("(");
sb.append(this.size());
sb.append(")[");
for (int i = 0; i < Math.min(10, this.size()); i++) {
if (i > 0)
sb.append(",");
sb.append(this.get(i));
}
if (this.size() >= 10)
sb.append("...");
sb.append("]");
return sb.toString();
}
}