package edu.berkeley.nlp.lm.array;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Arrays;
public final class LongArray implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -9133624434714616987L;
/**
* For some reason, some VMs will refuse to allocate long[] arrays of size
* Integer.MAX_VALUE, so we stick to at most MAX_VALUE / 2
*/
private static final int MAX_ARRAY_BITS = 30;
private static final int MAX_ARRAY_SIZE = 1 << MAX_ARRAY_BITS;
long size;
long[][] data;
// keep a reference to the lowest order array, since that will be used most often
private long[] first;
public LongArray(final long initialCapacity) {
this.size = 0;
allocFor(initialCapacity, null);
}
public static final class StaticMethods
{
public static LongArray newLongArray(final long maxKeySize, final long maxNumKeys) {
return newLongArray(maxKeySize, maxNumKeys, 10);
}
public static LongArray newLongArray(@SuppressWarnings("unused") final long maxKeySize, @SuppressWarnings("unused") final long maxNumKeys,
final long initCapacity) {
return new LongArray(initCapacity);
}
}
/**
* @param capacity
*/
private void allocFor(final long capacity, final long[][] old) {
final int numOuter = o(capacity) + 1;
final int numInner = i(capacity);
this.data = new long[numOuter][];
for (int i = 0; i < numOuter; ++i) {
final int currSize = (i == numOuter - 1) ? numInner : MAX_ARRAY_SIZE;
if (old == null || i >= old.length) {
data[i] = new long[currSize];
} else if (currSize == old[i].length) {
data[i] = old[i];
} else {
data[i] = Arrays.copyOf(old[i], currSize);
}
if (i == 0) first = data[i];
}
}
protected static final int o(final long l) {
return (int) (l >>> MAX_ARRAY_BITS);
}
protected static final int i(final long l) {
return (int) (l & (MAX_ARRAY_SIZE - 1));
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#set(long, long)
*/
public void set(final long pos, final long val) {
if (pos >= size) throw new ArrayIndexOutOfBoundsException("" + pos);
setHelp(pos, val);
}
/**
* @param pos
* @param val
*/
private void setHelp(final long pos, final long val) {
data[o(pos)][i(pos)] = val;
}
private void incrementHelp(final long pos, final long val) {
data[o(pos)][i(pos)] += val;
}
/*
* (non-Javadoc)
*
* @see
* edu.berkeley.nlp.mt.lm.util.collections.LongArray#setAndGrowIfNeeeded
* (long, long)
*/
public void setAndGrowIfNeeded(final long pos, final long val) {
ensureCapacity(pos + 1);
setGrowHelp(pos, val);
}
public void setAndGrowIfNeededFill(final long pos, final long val) {
ensureCapacity(pos + 1);
final long oldSize = size;
size = Math.max(size, pos + 1);
for (long i = oldSize; i < size; ++i)
setHelp(i, val);
}
/**
* @param pos
* @param val
*/
private void setGrowHelp(final long pos, final long val) {
size = Math.max(size, pos + 1);
setHelp(pos, val);
}
public void ensureCapacity(final long minCapacity) {
final long oldCapacity = sizeOf(data);
if (minCapacity > oldCapacity) {
final long[][] oldData = data;
long newCapacity = (oldCapacity * 3) / 2 + 1;
if (newCapacity < minCapacity) newCapacity = minCapacity;
allocFor(newCapacity, oldData);
}
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#get(long)
*/
public long get(final long pos) {
assert (pos < size) : this.getClass().getName() + " array index out of bounds";
return getHelp(pos);
}
private static long sizeOf(final long[][] a) {
long ret = 0;
for (int i = 0; i < a.length; ++i) {
ret += a[i].length;
}
return ret;
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#trim()
*/
public void trim() {
allocFor(size, data);
}
/**
* @param pos
* @return
*/
private long getHelp(final long pos) {
final int i = i(pos);
final int o = o(pos);
return o == 0 ? first[i] : data[o][i];
}
public static void main(final String[] argv) {
long mem = Runtime.getRuntime().maxMemory();
System.out.println("VM size is " + mem);
long pos = -9L + Integer.MAX_VALUE / 2;//;4L + Integer.MAX_VALUE;
final LongArray b = new LongArray(pos + 1);
final long val = 10000000000000L;
b.setAndGrowIfNeeded(pos, val);
final long z = b.get(pos);
assert z == val;
System.out.println("Finished with value " + z + " for " + val);
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#size()
*/
public long size() {
return size;
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#add(long)
*/
public boolean add(final long val) {
setAndGrowIfNeeded(size, val);
return true;
}
public boolean addWithFixedCapacity(final long val) {
setGrowHelp(size, val);
return true;
}
public void shift(final long src, final long dest, final int length) {
if (length == 0) return;
if (src == dest) return;
assert dest >= src;
final int oStart = o(src);
final int oEnd = o(src + length);
final int oDestStart = o(dest);
final int oDestEnd = o(dest + length);
if (dest + length >= size) {
setAndGrowIfNeeded(dest + length, 0);
}
if (oStart != oEnd || oDestStart != oDestEnd) {
for (long i = length - 1; i >= 0; --i) {
set(dest + i, get(src + i));
}
} else {
System.arraycopy(data[o(src)], i(src), data[o(dest)], i(dest), length);
}
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#trimToSize(long)
*/
public void trimToSize(final long size_) {
this.size = size_;
allocFor(size_, data);
}
/*
* (non-Javadoc)
*
* @see edu.berkeley.nlp.mt.lm.util.collections.LongArray#fill(long, long)
*/
public void fill(final long l, final long n) {
for (long i = 0; i < n; ++i)
setAndGrowIfNeeded(i, l);
}
public long linearSearch(final long key, final long rangeStart, final long rangeEnd, final long startIndex, final long emptyKey,
final boolean returnFirstEmptyIndex) {
for (long i = startIndex; i < rangeEnd; ++i) {
final long searchKey = getHelp(i);
if (searchKey == key) return i;
if (searchKey == emptyKey) return returnFirstEmptyIndex ? i : -1L;
}
for (long i = rangeStart; i < startIndex; ++i) {
final long searchKey = getHelp(i);
if (searchKey == key) return i;
if (searchKey == emptyKey) return returnFirstEmptyIndex ? i : -1L;
}
return -1L;
}
public void incrementCount(final long index, final long count) {
if (index >= size) {
setAndGrowIfNeeded(index, count);
} else {
incrementHelp(index, count);
}
}
}