tikhomirov@276: /* tikhomirov@276: * Copyright (c) 2011 TMate Software Ltd tikhomirov@276: * tikhomirov@276: * This program is free software; you can redistribute it and/or modify tikhomirov@276: * it under the terms of the GNU General Public License as published by tikhomirov@276: * the Free Software Foundation; version 2 of the License. tikhomirov@276: * tikhomirov@276: * This program is distributed in the hope that it will be useful, tikhomirov@276: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@276: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@276: * GNU General Public License for more details. tikhomirov@276: * tikhomirov@276: * For information on how to redistribute this software under tikhomirov@276: * the terms of a license other than GNU General Public License tikhomirov@276: * contact TMate Software at support@hg4j.com tikhomirov@276: */ tikhomirov@276: package org.tmatesoft.hg.internal; tikhomirov@276: tikhomirov@276: import java.util.NoSuchElementException; tikhomirov@276: tikhomirov@276: tikhomirov@276: /** tikhomirov@276: * Map implementation that uses plain int keys and performs with log n effectiveness. tikhomirov@276: * tikhomirov@276: * @author Artem Tikhomirov tikhomirov@276: * @author TMate Software Ltd. tikhomirov@276: */ tikhomirov@276: public class IntMap { tikhomirov@276: tikhomirov@276: private int[] keys; tikhomirov@276: private Object[] values; tikhomirov@276: private int size; tikhomirov@276: tikhomirov@276: public IntMap(int size) { tikhomirov@276: keys = new int[size <= 0 ? 16 : size]; tikhomirov@276: values = new Object[keys.length]; tikhomirov@276: } tikhomirov@276: tikhomirov@276: public int size() { tikhomirov@276: return size; tikhomirov@276: } tikhomirov@276: tikhomirov@276: public int firstKey() { tikhomirov@276: if (size == 0) { tikhomirov@276: throw new NoSuchElementException(); tikhomirov@276: } tikhomirov@276: return keys[0]; tikhomirov@276: } tikhomirov@276: tikhomirov@276: public int lastKey() { tikhomirov@276: if (size == 0) { tikhomirov@276: throw new NoSuchElementException(); tikhomirov@276: } tikhomirov@276: return keys[size-1]; tikhomirov@276: } tikhomirov@276: tikhomirov@276: public void trimToSize() { tikhomirov@276: if (size < keys.length) { tikhomirov@276: int[] newKeys = new int[size]; tikhomirov@276: Object[] newValues = new Object[size]; tikhomirov@276: System.arraycopy(keys, 0, newKeys, 0, size); tikhomirov@276: System.arraycopy(values, 0, newValues, 0, size); tikhomirov@276: keys = newKeys; tikhomirov@276: values = newValues; tikhomirov@276: } tikhomirov@276: } tikhomirov@276: tikhomirov@276: public void put(int key, V value) { tikhomirov@276: int ix = binarySearch(keys, size, key); tikhomirov@276: if (ix < 0) { tikhomirov@276: final int insertPoint = -ix - 1; tikhomirov@276: assert insertPoint <= size; // can't be greater, provided binarySearch didn't malfunction. tikhomirov@276: if (size == keys.length) { tikhomirov@278: int capInc = size >>> 2; // +25% tikhomirov@278: int newCapacity = size + (capInc < 2 ? 2 : capInc) ; tikhomirov@276: int[] newKeys = new int[newCapacity]; tikhomirov@276: Object[] newValues = new Object[newCapacity]; tikhomirov@276: System.arraycopy(keys, 0, newKeys, 0, insertPoint); tikhomirov@276: System.arraycopy(keys, insertPoint, newKeys, insertPoint+1, keys.length - insertPoint); tikhomirov@276: System.arraycopy(values, 0, newValues, 0, insertPoint); tikhomirov@276: System.arraycopy(values, insertPoint, newValues, insertPoint+1, values.length - insertPoint); tikhomirov@276: keys = newKeys; tikhomirov@276: values = newValues; tikhomirov@276: } else { tikhomirov@276: // arrays got enough capacity tikhomirov@276: if (insertPoint != size) { tikhomirov@276: System.arraycopy(keys, insertPoint, keys, insertPoint+1, keys.length - insertPoint - 1); tikhomirov@276: System.arraycopy(values, insertPoint, values, insertPoint+1, values.length - insertPoint - 1); tikhomirov@276: } tikhomirov@276: // else insertPoint is past known elements, no need to copy arrays tikhomirov@276: } tikhomirov@276: keys[insertPoint] = key; tikhomirov@276: values[insertPoint] = value; tikhomirov@276: size++; tikhomirov@276: } else { tikhomirov@276: values[ix] = value; tikhomirov@276: } tikhomirov@276: } tikhomirov@276: tikhomirov@276: public boolean containsKey(int key) { tikhomirov@276: return binarySearch(keys, size, key) >= 0; tikhomirov@276: } tikhomirov@276: tikhomirov@276: @SuppressWarnings("unchecked") tikhomirov@276: public V get(int key) { tikhomirov@276: int ix = binarySearch(keys, size, key); tikhomirov@276: if (ix >= 0) { tikhomirov@276: return (V) values[ix]; tikhomirov@276: } tikhomirov@276: return null; tikhomirov@276: } tikhomirov@281: tikhomirov@281: public void remove(int key) { tikhomirov@281: int ix = binarySearch(keys, size, key); tikhomirov@281: if (ix >= 0) { tikhomirov@281: if (ix <= size - 1) { tikhomirov@281: System.arraycopy(keys, ix+1, keys, ix, size - ix - 1); tikhomirov@281: System.arraycopy(values, ix+1, values, ix, size - ix - 1); tikhomirov@281: } // if ix points to last element, no reason to attempt a copy tikhomirov@281: size--; tikhomirov@281: keys[size] = 0; tikhomirov@281: values[size] = null; tikhomirov@281: } tikhomirov@281: } tikhomirov@281: tikhomirov@281: /** tikhomirov@281: * Forget first N entries (in natural order) in the map. tikhomirov@281: */ tikhomirov@281: @Experimental tikhomirov@281: public void removeFromStart(int count) { tikhomirov@281: if (count > 0 && count <= size) { tikhomirov@281: if (count < size) { tikhomirov@281: System.arraycopy(keys, count, keys, 0, size - count); tikhomirov@281: System.arraycopy(values, count, values, 0, size - count); tikhomirov@281: } tikhomirov@281: for (int i = size - count; i < size; i++) { tikhomirov@281: keys[i] = 0; tikhomirov@281: values[i] = null; tikhomirov@281: } tikhomirov@281: size -= count; tikhomirov@281: } tikhomirov@281: } tikhomirov@281: tikhomirov@281: tikhomirov@276: tikhomirov@276: // copy of Arrays.binarySearch, with upper search limit as argument tikhomirov@276: private static int binarySearch(int[] a, int high, int key) { tikhomirov@276: int low = 0; tikhomirov@276: high--; tikhomirov@276: tikhomirov@276: while (low <= high) { tikhomirov@276: int mid = (low + high) >> 1; tikhomirov@276: int midVal = a[mid]; tikhomirov@276: tikhomirov@276: if (midVal < key) tikhomirov@276: low = mid + 1; tikhomirov@276: else if (midVal > key) tikhomirov@276: high = mid - 1; tikhomirov@276: else tikhomirov@276: return mid; // key found tikhomirov@276: } tikhomirov@276: return -(low + 1); // key not found. tikhomirov@276: } tikhomirov@276: }