package org.yamcs.utils;
import java.io.Serializable;
import java.util.Arrays;
import java.util.PrimitiveIterator;
/**
* sorted int array
*
*
* @author nm
*
*/
public class SortedIntArray implements Serializable {
static final long serialVersionUID = 1L;
public static int DEFAULT_CAPACITY = 10;
private int[] a;
private int length;
//caches the hashCode
private int hash;
/**
* Creates a sorted int array with a default initial capacity
*
*/
public SortedIntArray() {
a = new int[DEFAULT_CAPACITY];
}
/**
* Creates a sorted int array with a given initial capacity
*
* @param capacity
*/
public SortedIntArray(int capacity) {
a = new int[capacity];
}
/**
* Creates the SortedIntArray by copying all values from the input array and sorting them
*
* @param array
*/
public SortedIntArray(int... array) {
length = array.length;
a = Arrays.copyOf(array, length);
Arrays.sort(a);
}
/**
* Inserts value to the array and return the position on which has been inserted
*
* @param x - value to be inserted
* @return the position on which the value has been inserted
*/
public int insert(int x) {
int pos = Arrays.binarySearch(a, 0, length, x);
if( pos<0 ) {
pos = -pos-1;
}
ensureCapacity(length+1);
System.arraycopy(a, pos, a, pos+1, length-pos);
a[pos] = x;
length++;
return pos;
}
/**
* performs a binary search in the array.
*
* @see java.util.Arrays#binarySearch(int[], int)
* @param x
* @return result of the binarySearch, @see java.util.Arrays#binarySearch(int[], int)
*/
public int search(int x) {
return Arrays.binarySearch(a, 0, length, x);
}
/**
* get element at position
* @param pos
* @return the element at position
*/
public int get(int pos) {
if(pos >= length) {
throw new IndexOutOfBoundsException("Index: "+pos+" length: "+length);
}
return a[pos];
}
private void ensureCapacity(int minCapacity) {
if(minCapacity<=a.length) {
return;
}
int capacity = a.length;
int newCapacity = capacity + (capacity >> 1);
if(newCapacity<minCapacity) {
newCapacity = minCapacity;
}
a = Arrays.copyOf(a, newCapacity);
}
public boolean isEmpty() {
return a.length==0;
}
public int[] getArray() {
return Arrays.copyOf(a, length);
}
public int size() {
return length;
}
/**
* Constructs an ascending iterator starting from a specified value (inclusive)
*
* @param startFrom
* @return an iterator starting from the specified value
*/
public PrimitiveIterator.OfInt getAscendingIterator(int startFrom) {
return new PrimitiveIterator.OfInt() {
int pos;
{
pos = search(startFrom);
if(pos<0) {
pos = -pos-1;
}
}
@Override
public boolean hasNext() {
return pos < length;
}
@Override
public int nextInt() {
return a[pos++];
}
};
}
/**
* Constructs an descending iterator starting from a specified value (exclusive)
*
* @param startFrom
* @return an descending iterator starting from the specified value
*/
public PrimitiveIterator.OfInt getDescendingIterator(int startFrom) {
return new PrimitiveIterator.OfInt() {
int pos;
{
pos = search(startFrom);
if(pos<0) {
pos = -pos-1;
}
pos--;
}
@Override
public boolean hasNext() {
return pos>=0;
}
@Override
public int nextInt() {
return a[pos--];
}
};
}
public String toString() {
StringBuilder b = new StringBuilder();
int n = length-1;
b.append('[');
for (int i = 0;; i++) {
b.append(a[i]);
if(i==n)
return b.append(']').toString();
b.append(", ");
}
}
@Override
public int hashCode() {
int h = hash;
if (h == 0 && length > 0) {
h = 1;
for (int i = 0; i < length; i++) {
h = 31 * h + a[i];
}
hash = h;
}
return h;
}
/**
* Performs a binary search and returns true if this array contains the value.
*
* @param x - value to check
* @return true of the array contains the specified value
*
*/
public boolean contains(int x) {
return Arrays.binarySearch(a, 0, length, x)>=0;
}
public byte[] encodeToVarIntArray() {
byte[] buf = new byte[length*4];
if(length==0) {
return buf;
}
int pos = VarIntUtil.writeVarint32(buf, 0, a[0]);
for(int i=1; i<length; i++) {
pos = VarIntUtil.writeVarint32(buf, pos, (a[i]-a[i-1]));
}
if(pos==buf.length) {
return buf;
} else {
return Arrays.copyOf(buf, pos);
}
}
public static SortedIntArray decodeFromVarIntArray(byte[] buf) {
if(buf.length==0) {
return new SortedIntArray(0);
}
SortedIntArray sia = new SortedIntArray();
VarIntUtil.ArrayDecoder ad = VarIntUtil.newArrayDecoder(buf);
int s=0;
while(ad.hasNext()) {
s+=ad.next();
sia.insert(s);
}
return sia;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
SortedIntArray other = (SortedIntArray) obj;
if (length != other.length) return false;
for(int i=0; i<length; i++) {
if(a[i]!=other.a[i]) return false;
}
return true;
}
}