package org.basex.util.list;
import java.util.Arrays;
import org.basex.util.Array;
import org.basex.util.Token;
import org.basex.util.TokenBuilder;
import org.basex.util.Util;
/**
* This is a simple container for native integers.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public class IntList extends ElementList {
/** Element container. */
protected int[] list;
/**
* Default constructor.
*/
public IntList() {
this(CAP);
}
/**
* Constructor, specifying an initial array capacity.
* @param c array capacity
*/
public IntList(final int c) {
list = new int[c];
}
/**
* Constructor.
* @param f resize factor
*/
public IntList(final double f) {
this();
factor = f;
}
/**
* Constructor, specifying an initial array.
* @param a initial array
*/
public IntList(final int[] a) {
list = a;
size = a.length;
}
/**
* Adds an entry to the array.
* @param e entry to be added
*/
public final void add(final int e) {
if(size == list.length) list = Arrays.copyOf(list, newSize());
list[size++] = e;
}
/**
* Returns the element at the specified index position.
* @param i index
* @return element
*/
public final int get(final int i) {
return list[i];
}
/**
* Sets an element at the specified index position.
* @param i index
* @param e element to be set
*/
public final void set(final int i, final int e) {
if(i >= list.length) list = Arrays.copyOf(list, newSize(i + 1));
list[i] = e;
size = Math.max(size, i + 1);
}
/**
* Checks if the specified element is found in the list.
* @param e element to be found
* @return result of check
*/
public final boolean contains(final int e) {
for(int i = 0; i < size; ++i) if(list[i] == e) return true;
return false;
}
/**
* Inserts elements at the specified index position.
* @param i index
* @param e elements to be inserted
*/
public final void insert(final int i, final int[] e) {
final int l = e.length;
if(l == 0) return;
if(size + l > list.length) list = Arrays.copyOf(list, newSize(size + l));
Array.move(list, i, l, size - i);
System.arraycopy(e, 0, list, i, l);
size += l;
}
/**
* Deletes the element at the specified position.
* @param i position to delete
*/
public final void delete(final int i) {
Array.move(list, i + 1, -1, --size - i);
}
/**
* Adds a difference to all elements starting from the specified index.
* @param e difference
* @param i index
*/
public final void move(final int e, final int i) {
for(int a = i; a < size; a++) list[a] += e;
}
/**
* Returns the uppermost element from the stack.
* @return the uppermost element
*/
public final int peek() {
return list[size - 1];
}
/**
* Pops the uppermost element from the stack.
* @return the popped element
*/
public final int pop() {
return list[--size];
}
/**
* Pushes an element onto the stack.
* @param val element
*/
public final void push(final int val) {
add(val);
}
/**
* Searches the specified element via binary search.
* Note that all elements must be sorted.
* @param e element to be found
* @return index of the search key, or the negative insertion point - 1
*/
public final int sortedIndexOf(final int e) {
return Arrays.binarySearch(list, 0, size, e);
}
/**
* Returns an array with all elements.
* @return array
*/
public final int[] toArray() {
return Arrays.copyOf(list, size);
}
/**
* Sorts the data.
* @return self reference
*/
public IntList sort() {
Arrays.sort(list, 0, size);
return this;
}
/**
* Sorts the data in the order of the specified token array.
* Note that the input array will be resorted as well.
* The algorithm is derived from {@link Arrays#sort(int[])}.
* @param tok token array to sort by
* @param num numeric sort
* @param asc ascending
*/
public final void sort(final byte[][] tok, final boolean num,
final boolean asc) {
sort(0, size, num, asc, tok);
}
/**
* Sorts the data in the order of the specified numeric array.
* Note that the input array will be resorted as well.
* The algorithm is derived from {@link Arrays#sort(int[])}.
* @param num token array to sort by
* @param asc ascending
*/
public final void sort(final double[] num, final boolean asc) {
sort(0, size, asc, num);
}
/**
* Sorts the array.
* @param s offset
* @param e length
* @param g numeric sort
* @param f ascending/descending sort
* @param t sort tokens
*/
private void sort(final int s, final int e, final boolean g,
final boolean f, final byte[][] t) {
if(e < 7) {
for(int i = s; i < e + s; ++i) {
for(int j = i; j > s; j--) {
final int h = g ? s(t[j - 1], t[j]) : d(t[j - 1], t[j]);
if(f ? h < 0 : h > 0) break;
s(j, j - 1, t);
}
}
return;
}
int m = s + (e >> 1);
if(e > 7) {
int l = s;
int n = s + e - 1;
if(e > 40) {
final int k = e >>> 3;
l = m(l, l + k, l + (k << 1));
m = m(m - k, m, m + k);
n = m(n - (k << 1), n - k, n);
}
m = m(l, m, n);
}
final byte[] v = t[m];
int a = s, b = a, c = s + e - 1, d = c;
while(true) {
while(b <= c) {
final int h = g ? s(t[b], v) : d(t[b], v);
if(f ? h > 0 : h < 0) break;
if(h == 0) s(a++, b, t);
++b;
}
while(c >= b) {
final int h = g ? s(t[c], v) : d(t[c], v);
if(f ? h < 0 : h > 0) break;
if(h == 0) s(c, d--, t);
--c;
}
if(b > c) break;
s(b++, c--, t);
}
int k;
final int n = s + e;
k = Math.min(a - s, b - a);
s(s, b - k, k, t);
k = Math.min(d - c, n - d - 1);
s(b, n - k, k, t);
if((k = b - a) > 1) sort(s, k, g, f, t);
if((k = d - c) > 1) sort(n - k, k, g, f, t);
}
/**
* Sorts the array.
* @param s offset
* @param e length
* @param f ascending/descending sort
* @param t sort tokens
*/
private void sort(final int s, final int e, final boolean f,
final double[] t) {
if(e < 7) {
for(int i = s; i < e + s; ++i) {
for(int j = i; j > s; j--) {
final double h = t[j - 1] - t[j];
if(f ? h < 0 : h > 0) break;
s(j, j - 1, t);
}
}
return;
}
int m = s + (e >> 1);
if(e > 7) {
int l = s;
int n = s + e - 1;
if(e > 40) {
final int k = e >>> 3;
l = m(l, l + k, l + (k << 1));
m = m(m - k, m, m + k);
n = m(n - (k << 1), n - k, n);
}
m = m(l, m, n);
}
final double v = t[m];
int a = s, b = a, c = s + e - 1, d = c;
while(true) {
while(b <= c) {
final double h = t[b] - v;
if(f ? h > 0 : h < 0) break;
if(h == 0) s(a++, b, t);
++b;
}
while(c >= b) {
final double h = t[c] - v;
if(f ? h < 0 : h > 0) break;
if(h == 0) s(c, d--, t);
--c;
}
if(b > c) break;
s(b++, c--, t);
}
int k;
final int n = s + e;
k = Math.min(a - s, b - a);
s(s, b - k, k, t);
k = Math.min(d - c, n - d - 1);
s(b, n - k, k, t);
if((k = b - a) > 1) sort(s, k, f, t);
if((k = d - c) > 1) sort(n - k, k, f, t);
}
/**
* Compares two numeric tokens and returns an integer.
* @param a first token
* @param b second token
* @return result
*/
private static int s(final byte[] a, final byte[] b) {
final double n = Token.toDouble(a) - Token.toDouble(b);
return n > 0 ? 1 : n < 0 ? -1 : 0;
}
/**
* Compares two tokens and returns an integer.
* @param a first token
* @param b second token
* @return result
*/
private static int d(final byte[] a, final byte[] b) {
return a == null ? b == null ? 0 : -1 : b == null ? 1 : Token.diff(a, b);
}
/**
* Swaps two array elements.
* @param a first offset
* @param b second offset
* @param t sort tokens
*/
private void s(final int a, final int b, final byte[][] t) {
final int l = list[a];
list[a] = list[b];
list[b] = l;
final byte[] c = t[a];
t[a] = t[b];
t[b] = c;
}
/**
* Swaps two array elements.
* @param a first offset
* @param b second offset
* @param t sort tokens
*/
private void s(final int a, final int b, final double[] t) {
final int l = list[a];
list[a] = list[b];
list[b] = l;
final double c = t[a];
t[a] = t[b];
t[b] = c;
}
/**
* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
* @param a first offset
* @param b second offset
* @param n number of elements
* @param t sort tokens
*/
private void s(final int a, final int b, final int n, final byte[][] t) {
for(int i = 0; i < n; ++i) s(a + i, b + i, t);
}
/**
* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
* @param a first offset
* @param b second offset
* @param n number of elements
* @param t sort tokens
*/
private void s(final int a, final int b, final int n, final double[] t) {
for(int i = 0; i < n; ++i) s(a + i, b + i, t);
}
/**
* Returns the index of the median of the three indexed integers.
* @param a first offset
* @param b second offset
* @param c thirst offset
* @return median
*/
private int m(final int a, final int b, final int c) {
return list[a] < list[b] ?
list[b] < list[c] ? b : list[a] < list[c] ? c : a :
list[b] > list[c] ? b : list[a] > list[c] ? c : a;
}
@Override
public String toString() {
final TokenBuilder tb = new TokenBuilder(Util.name(this) + '[');
for(int i = 0; i < size; ++i) tb.add((i == 0 ? "" : ", ") + list[i]);
return tb.add(']').toString();
}
}