package uk.ac.manchester.cs.chainsaw; /* This file is part of the JFact DL reasoner Copyright 2011 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/ import java.util.Arrays; import javax.annotation.Nullable; /** * @author ignazio */ public class FastSetSimple extends AbstractFastSet { protected static final int DEFAULTSIZE = 16; @Nullable protected int[] values; protected int size = 0; /** * Default constructor. */ public FastSetSimple() { super(); } /** * @param c1 c1 * @param c2 c2 */ @SuppressWarnings("null") public FastSetSimple(FastSetSimple c1, FastSetSimple c2) { values = new int[(c1.size + c2.size) / DEFAULTSIZE * DEFAULTSIZE + DEFAULTSIZE]; int i = 0; int j = 0; int index = 0; for (; i < c1.size && j < c2.size; index++) { if (c1.values[i] < c2.values[j]) { values[index] = c1.values[i]; i++; } else if (c2.values[j] < c1.values[i]) { values[index] = c2.values[j]; j++; } // the result must be a set: equal elements advance both indexes else if (c1.values[i] == c2.values[j]) { values[index] = c1.values[i]; i++; j++; } } // remaining elements in one set or the other if (i < c1.size) { for (; i < c1.size; i++, index++) { values[index] = c1.values[i]; } // new size here size = index; } else { for (; j < c2.size; j++, index++) { values[index] = c2.values[j]; } // new size here size = index; } } @SuppressWarnings("null") protected int insertionIndex(int key) { assert values != null; if (key < values[0]) { return -1; } if (key > values[size - 1]) { return -size - 1; } int lowerbound = 0; if (size < LIMIT) { for (; lowerbound < size; lowerbound++) { if (values[lowerbound] > key) { return -lowerbound - 1; } if (values[lowerbound] == key) { return lowerbound; } } return -lowerbound - 1; } int upperbound = size - 1; while (lowerbound <= upperbound) { int delta = upperbound - lowerbound; int intermediate = lowerbound + delta / 2; if (values[intermediate] == key) { return intermediate; } if (values[intermediate] < key) { lowerbound = intermediate + 1; } else { upperbound = intermediate - 1; } } return -lowerbound - 1; } @Override public int get(int i) { if (values != null) { return values[i]; } throw new IllegalArgumentException("Illegal argument " + i + ": no such element"); } protected void init() { values = new int[DEFAULTSIZE]; size = 0; } @SuppressWarnings("null") @Override public boolean add(int e) { int pos = -1; if (values == null) { init(); // pos stays at -1, in an empty set that's the place to start - it // will become 0 } else { // else find the right place pos = insertionIndex(e); } if (pos > -1) { return false; } int i = -pos - 1; // i is now the insertion point if (i >= values.length || size >= values.length) { // no space left, increase values = Arrays.copyOf(values, 2 * values.length); } // size ensured, shift and insert now for (int j = size - 1; j >= i; j--) { values[j + 1] = values[j]; } values[i] = e; // increase used size size++; return true; } @SuppressWarnings("null") @Override public void addAll(FastSet c) { if (c.isEmpty()) { return; } // merge two sorted arrays: how bad can it be? if (values == null) { // extreme case: just copy the other set values = Arrays.copyOf(((FastSetSimple) c).values, c.size()); size = c.size(); return; } int newsize = size + c.size(); int[] merge = new int[newsize / DEFAULTSIZE * DEFAULTSIZE + DEFAULTSIZE]; int i = 0; int j = 0; int index = 0; for (; i < size() && j < c.size(); index++) { if (values[i] < c.get(j)) { merge[index] = values[i]; i++; } else if (c.get(j) < values[i]) { merge[index] = c.get(j); j++; } // the result must be a set: equal elements advance both indexes else if (values[i] == c.get(j)) { merge[index] = values[i]; i++; j++; } } // remaining elements in one set or the other if (i < size()) { for (; i < size(); i++, index++) { merge[index] = values[i]; } // new size here newsize = index; } else { for (; j < c.size(); j++, index++) { merge[index] = c.get(j); } // new size here newsize = index; } values = merge; size = newsize; } @Override public void clear() { values = null; size = 0; } @Override public boolean contains(int o) { if (values != null) { return insertionIndex(o) > -1; } return false; } @Override public boolean containsAll(FastSet c) { if (c.isEmpty()) { return true; } if (isEmpty()) { return false; } if (c.size() > size) { return false; } if (get(0) > c.get(0) || get(size - 1) < c.get(c.size() - 1)) { // c boundaries are outside this set return false; } int i = 0; int j = 0; int currentValue; while (j < c.size()) { currentValue = c.get(j); boolean found = false; while (i < size) { if (get(i) == currentValue) { // found the current value, next element in c - increase j found = true; break; } if (get(i) > currentValue) { // found a value larger than the value it's looking for - c // is not contained return false; } // get(i) is < than current value: check next i i++; } if (!found) { // finished exploring this and currentValue was not found - it // happens if currentValue < any element in this set return false; } j++; } return true; } @Override public boolean isEmpty() { return values == null; } @Override public boolean containsAny(FastSet c) { if (c.isEmpty() || size == 0) { return false; } int i = 0; int j = 0; int currentValue; while (j < c.size()) { currentValue = c.get(j); while (i < size) { if (get(i) == currentValue) { // found the current value, next element in c - increase j return true; } if (get(i) > currentValue) { // found a value larger than the value it's looking for - c // is not contained break; } // get(i) is < than current value: check next i i++; } j++; } return false; } @Override public void remove(int o) { if (values == null) { return; } int i = insertionIndex(o); removeAt(i); } @Override public int size() { return size; } @Override public int[] toIntArray() { if (values == null) { return new int[0]; } return Arrays.copyOf(values, size); } @Override public boolean intersect(FastSet f) { return containsAny(f); } @SuppressWarnings("null") @Override public void removeAt(int i) { if (values == null) { return; } if (i > -1 && i < size) { if (size == 1) { values = null; size = 0; return; } for (int j = i; j < size - 1; j++) { values[j] = values[j + 1]; } size--; } if (size == 0) { values = null; } } @SuppressWarnings("null") @Override public void removeAll(int i, int end) { if (values == null) { return; } if (end < -1 || end < i || end > size || i < -1 || i > size) { throw new IllegalArgumentException( "illegal arguments: " + i + " " + end + " size: " + size); } if (size == 1 || i == 0 && end == size) { values = null; size = 0; return; } if (end == size) { size = i; } else { int delta = end - i; for (int j = i; j < size - delta; j++) { values[j] = values[j + delta]; } size -= delta; } if (size == 0) { values = null; } } @SuppressWarnings("null") @Override public void removeAllValues(int... vals) { if (values == null) { return; } if (vals.length == 1) { remove(vals[0]); return; } Arrays.sort(vals); int originalsize = size; for (int i = 0, j = 0; i < originalsize && j < vals.length; i++) { if (values[i] == vals[j]) { values[i] = Integer.MAX_VALUE; size--; j++; } } if (size == 0) { values = null; } else { Arrays.sort(values, 0, originalsize); } } @Override public void completeSet(int value) { for (int i = 0; i <= value; i++) { add(i); } // XXX notice: these sets go to negative numbers. Is this the best way? } }