/** * Copyright (c) 2009 International Health Terminology Standards Development * Organisation * * Licensed 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. */ /** * Copyright CSIRO Australian e-Health Research Centre (http://aehrc.com). * All rights reserved. Use is subject to license terms and conditions. */ package au.csiro.snorocket.core.util; /** * Implementation of the IConceptSet API that does not support clear() or * remove()/removeAll(). Set entries are stored in sorted order to allow for * O(log n) lookup time. Inserts require copying all larger values to make * remove for the inserted value. Worst-case insert performance happens when * elements are added largest to smallest. * * @author law223 * */ final public class SparseConceptSet implements IConceptSet { /** * Serialisation version. */ private static final long serialVersionUID = 1L; private int[] items; private int size; /** * * @param capacity * initial size of underlying array */ public SparseConceptSet(final int capacity) { items = new int[capacity]; size = 0; items[size] = -1; } public SparseConceptSet() { this(10); } public synchronized void add(final int concept) { int low = 0; int high = size; while ((high - low) > 16) { // binary search int probe = (low + high) >> 1; // don't need to worry about overflow if (items[probe] > concept) { low = probe + 1; } else if (items[probe] < concept) { high = probe - 1; } else { // concept found - nothing to do return; } } // fall through to linear search while (concept < items[low]) { low++; } if (concept > items[low]) { size++; if (items.length == size) { final int increment = 10; final int[] newItems = new int[size + increment]; System.arraycopy(items, 0, newItems, 0, low); System.arraycopy(items, low, newItems, low + 1, size - low); items = newItems; // System.err.println(size + ", " + i + ", " + items.length + // ", " + (size-i)); } else { System.arraycopy(items, low, items, low + 1, size - low); } items[low] = concept; } // else items[i] == concept, so do nothing else if (concept != items[low]) { throw new AssertionError( "Internal error detected, expecting items[i] == concept where i = " + low + ", items[i] = " + items[low] + ", and concept = " + concept); } } public void addAll(final IConceptSet set) { for (final IntIterator itr = set.iterator(); itr.hasNext();) { add(itr.next()); } } public void clear() { throw new UnsupportedOperationException(); } public boolean contains(final int concept) { int low = 0; int high = size; while ((high - low) > 16) { // binary search int probe = (low + high) >> 1; // don't need to worry about overflow if (items[probe] > concept) { low = probe + 1; } else if (items[probe] < concept) { high = probe - 1; } else { return true; } } // fall through to linear search while (low < items.length && concept < items[low]) { low++; } return low < items.length && concept == items[low]; } public boolean containsAll(IConceptSet concepts) { if (concepts.isEmpty()) { return true; } final IConceptSet s = IConceptSet.FACTORY.createConceptSet(concepts); s.removeAll(this); return s.isEmpty(); // return false; } public boolean isEmpty() { return 0 == size(); } public synchronized IntIterator iterator() { return new SparseConceptSetIntIterator(items, size); } public void remove(int concept) { throw new UnsupportedOperationException(); } public void removeAll(IConceptSet set) { throw new UnsupportedOperationException(); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{"); for (int i = 0; i < size; i++) { sb.append(items[i]); if (i + 1 < size) { sb.append(", "); } } sb.append("}"); return sb.toString(); // return size + ":" +Arrays.toString(items); } public int size() { return size; } public synchronized void grow(int newSize) { assert newSize >= size; final int[] newItems = new int[newSize]; System.arraycopy(items, 0, newItems, 0, size); items = newItems; } public int[] toArray() { int[] res = new int[size]; for (int i = 0; i < size; i++) { res[i] = items[i]; } return res; } }