package org.apache.lucene.util.collections;
import java.util.Arrays;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A Class wrapper for a grow-able int[] which can be sorted and intersect with
* other IntArrays.
*
* @lucene.experimental
*/
public class IntArray {
/**
* The int[] which holds the data
*/
private int[] data;
/**
* Holds the number of items in the array.
*/
private int size;
/**
* A flag which indicates whether a sort should occur of the array is
* already sorted.
*/
private boolean shouldSort;
/**
* Construct a default IntArray, size 0 and surly a sort should not occur.
*/
public IntArray() {
init(true);
}
private void init(boolean realloc) {
size = 0;
if (realloc) {
data = new int[0];
}
shouldSort = false;
}
/**
* Intersects the data with a given {@link IntHashSet}.
*
* @param set
* A given ArrayHashSetInt which holds the data to be intersected
* against
*/
public void intersect(IntHashSet set) {
int newSize = 0;
for (int i = 0; i < size; ++i) {
if (set.contains(data[i])) {
data[newSize] = data[i];
++newSize;
}
}
this.size = newSize;
}
/**
* Intersects the data with a given IntArray
*
* @param other
* A given IntArray which holds the data to be intersected agains
*/
public void intersect(IntArray other) {
sort();
other.sort();
int myIndex = 0;
int otherIndex = 0;
int newSize = 0;
if (this.size > other.size) {
while (otherIndex < other.size && myIndex < size) {
while (otherIndex < other.size
&& other.data[otherIndex] < data[myIndex]) {
++otherIndex;
}
if (otherIndex == other.size) {
break;
}
while (myIndex < size && other.data[otherIndex] > data[myIndex]) {
++myIndex;
}
if (other.data[otherIndex] == data[myIndex]) {
data[newSize++] = data[myIndex];
++otherIndex;
++myIndex;
}
}
} else {
while (otherIndex < other.size && myIndex < size) {
while (myIndex < size && other.data[otherIndex] > data[myIndex]) {
++myIndex;
}
if (myIndex == size) {
break;
}
while (otherIndex < other.size
&& other.data[otherIndex] < data[myIndex]) {
++otherIndex;
}
if (other.data[otherIndex] == data[myIndex]) {
data[newSize++] = data[myIndex];
++otherIndex;
++myIndex;
}
}
}
this.size = newSize;
}
/**
* Return the size of the Array. Not the allocated size, but the number of
* values actually set.
*
* @return the (filled) size of the array
*/
public int size() {
return size;
}
/**
* Adds a value to the array.
*
* @param value
* value to be added
*/
public void addToArray(int value) {
if (size == data.length) {
int[] newArray = new int[2 * size + 1];
System.arraycopy(data, 0, newArray, 0, size);
data = newArray;
}
data[size] = value;
++size;
shouldSort = true;
}
/**
* Equals method. Checking the sizes, than the values from the last index to
* the first (Statistically for random should be the same but for our
* specific use would find differences faster).
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof IntArray)) {
return false;
}
IntArray array = (IntArray) o;
if (array.size != size) {
return false;
}
sort();
array.sort();
boolean equal = true;
for (int i = size; i > 0 && equal;) {
--i;
equal = (array.data[i] == this.data[i]);
}
return equal;
}
/**
* Sorts the data. If it is needed.
*/
public void sort() {
if (shouldSort) {
shouldSort = false;
Arrays.sort(data, 0, size);
}
}
/**
* Calculates a hash-code for HashTables
*/
@Override
public int hashCode() {
int hash = 0;
for (int i = 0; i < size; ++i) {
hash = data[i] ^ (hash * 31);
}
return hash;
}
/**
* Get an element from a specific index.
*
* @param i
* index of which element should be retrieved.
*/
public int get(int i) {
if (i >= size) {
throw new ArrayIndexOutOfBoundsException(i);
}
return this.data[i];
}
public void set(int idx, int value) {
if (idx >= size) {
throw new ArrayIndexOutOfBoundsException(idx);
}
this.data[idx] = value;
}
/**
* toString or not toString. That is the question!
*/
@Override
public String toString() {
String s = "(" + size + ") ";
for (int i = 0; i < size; ++i) {
s += "" + data[i] + ", ";
}
return s;
}
/**
* Clear the IntArray (set all elements to zero).
* @param resize - if resize is true, then clear actually allocates
* a new array of size 0, essentially 'clearing' the array and freeing
* memory.
*/
public void clear(boolean resize) {
init(resize);
}
}