package org.opensolaris.os.dtrace;
import java.beans.*;
import java.io.*;
import java.util.*;
public final class LogLinearDistribution extends Distribution
implements Serializable, Comparable <LogLinearDistribution>
{
static final long serialVersionUID = 6271156690706677711L;
static final long UINT16_MAX = 0xffff;
static final long FACTOR_SHIFT = 48;
static final long LOW_SHIFT = 32;
static final long HIGH_SHIFT = 16;
static final long NSTEP_SHIFT = 0;
private static long unpack(long x, long thing) {
return (x & (UINT16_MAX << thing)) >> thing;
}
private long encValue;
private long base;
static {
try {
BeanInfo info = Introspector.getBeanInfo(
LogLinearDistribution.class);
PersistenceDelegate persistenceDelegate =
new DefaultPersistenceDelegate(
new String[] { "encValue", "base", "buckets" });
BeanDescriptor d = info.getBeanDescriptor();
d.setValue("persistenceDelegate", persistenceDelegate);
} catch (IntrospectionException e) {
System.out.println(e);
}
}
private LogLinearDistribution(long constant, long[] frequencies) {
super(0, constant, frequencies);
encValue = constant;
}
public LogLinearDistribution(long enc, long base,
List<Bucket> frequencies) {
super(frequencies);
encValue = enc;
base = base;
initialize();
}
public LogLinearDistribution(long scaleFactor, long lowMagnitude,
long highMagnitude, long bucketSteps, long baseVal,
List<Bucket> frequencies) {
super(frequencies);
encValue = (scaleFactor << FACTOR_SHIFT) | (lowMagnitude << LOW_SHIFT) |
(highMagnitude << HIGH_SHIFT) | (bucketSteps << NSTEP_SHIFT);
base = baseVal;
initialize();
}
private long[][] rangeCache = null;
private void fillRangeCache(long constant, int len) {
long value = 1;
long next, step;
long low, high, nsteps, factor;
int order, bucket = 0;
low = unpack(constant, LOW_SHIFT);
high = unpack(constant, HIGH_SHIFT);
nsteps = unpack(constant, NSTEP_SHIFT);
factor = unpack(constant, FACTOR_SHIFT);
if (rangeCache == null)
rangeCache = new long[len][2];
for (order = 0; order < low; order++)
value *= factor;
base = value;
rangeCache[bucket][0] = Long.MIN_VALUE;
rangeCache[bucket][1] = value - 1;
bucket++;
next = value * factor;
step = (next > nsteps) ? (next / nsteps) : 1;
while (order <= high) {
rangeCache[bucket][0] = value;
rangeCache[bucket][1] = value + step - 1;
bucket++;
if ((value += step) != next)
continue;
next = value * factor;
step = (next > nsteps) ? (next / nsteps) : 1;
order++;
}
rangeCache[bucket][0] = value;
rangeCache[bucket][1] = Long.MAX_VALUE;
}
@Override
long[] getBucketRange(int i, int len, long base, long constant) {
if (rangeCache == null)
fillRangeCache(constant, len);
return rangeCache[i];
}
@Override
long[] getBucketRange(int i, int len) {
return getBucketRange(i, len, 0, encValue);
}
public Number getValue() {
double total = 0;
List<Distribution.Bucket> buckets = getBuckets();
for (Distribution.Bucket bucket : buckets)
total += ((double)bucket.getFrequency() * (double)bucket.getMin());
return (Double.valueOf(total));
}
private long getZeroBucketValue() {
for (Distribution.Bucket b : this) {
if (b.getMin() == 0) {
return b.getFrequency();
}
}
return 0;
}
public int compareTo(LogLinearDistribution d) {
Number v1 = getValue();
Number v2 = getValue();
double d1 = v1.doubleValue();
double d2 = v2.doubleValue();
int cmp = (d1 < d2 ? -1 : (d1 > d2 ? 1 : 0));
if (cmp == 0) {
long z1 = getZeroBucketValue();
long z2 = d.getZeroBucketValue();
cmp = (z1 < z2 ? -1 : (z1 > z2 ? 1 : 0));
}
return (cmp);
}
public long getBase() {
return base;
}
public long getEncValue() {
return encValue;
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
try {
initialize();
} catch (Exception e) {
InvalidObjectException x = new InvalidObjectException(
e.getMessage());
x.initCause(e);
throw x;
}
}
}