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@276: int newCapacity = size + (size >>> 2); 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@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: tikhomirov@276: public static void main(String[] args) { tikhomirov@276: IntMap m = new IntMap(-1); tikhomirov@276: m.put(18, "18"); tikhomirov@276: m.put(1, "1"); tikhomirov@276: m.put(9, "9"); tikhomirov@276: m.put(20, "20"); tikhomirov@276: m.put(2, "2"); tikhomirov@276: m.put(3, "3"); tikhomirov@276: m.put(21, "21"); tikhomirov@276: m.put(15, "15"); tikhomirov@276: m.put(12, "12"); tikhomirov@276: m.put(11, "11"); tikhomirov@276: m.put(31, "31"); tikhomirov@276: System.out.printf("%d [%d..%d]\n", m.size(), m.firstKey(), m.lastKey()); tikhomirov@276: for (int i = m.firstKey(); i <= m.lastKey(); i++) { tikhomirov@276: if (m.containsKey(i)) { tikhomirov@276: System.out.printf("@%02d:%s\n", i, m.get(i)); tikhomirov@276: } tikhomirov@276: } tikhomirov@276: } tikhomirov@276: }