package de.danoeh.antennapod.core.util; import java.util.Arrays; /** * Fast and memory efficient long to long map */ public class LongIntMap { private long[] keys; private int[] values; private int size; /** * Creates a new LongLongMap containing no mappings. */ public LongIntMap() { this(10); } /** * Creates a new SparseLongArray containing no mappings that will not * require any additional memory allocation to store the specified * number of mappings. If you supply an initial capacity of 0, the * sparse array will be initialized with a light-weight representation * not requiring any additional array allocations. */ public LongIntMap(int initialCapacity) { if(initialCapacity < 0) { throw new IllegalArgumentException("initial capacity must be 0 or higher"); } keys = new long[initialCapacity]; values = new int[initialCapacity]; size = 0; } /** * Increases size of array if needed */ private void growIfNeeded() { if (size == keys.length) { // Resize. long[] newKeysArray = new long[size * 3 / 2 + 10]; int[] newValuesArray = new int[size * 3 / 2 + 10]; System.arraycopy(keys, 0, newKeysArray, 0, size); System.arraycopy(values, 0, newValuesArray, 0, size); keys = newKeysArray; values = newValuesArray; } } /** * Gets the long mapped from the specified key, or <code>0</code> * if no such mapping has been made. */ public int get(long key) { return get(key, 0); } /** * Gets the long mapped from the specified key, or the specified value * if no such mapping has been made. */ public int get(long key, int valueIfKeyNotFound) { int index = indexOfKey(key); if(index >= 0) { return values[index]; } else { return valueIfKeyNotFound; } } /** * Removes the mapping from the specified key, if there was any. */ public boolean delete(long key) { int index = indexOfKey(key); if (index >= 0) { removeAt(index); return true; } else { return false; } } /** * Removes the mapping at the given index. */ public void removeAt(int index) { System.arraycopy(keys, index + 1, keys, index, size - (index + 1)); System.arraycopy(values, index + 1, values, index, size - (index + 1)); size--; } /** * Adds a mapping from the specified key to the specified value, * replacing the previous mapping from the specified key if there * was one. */ public void put(long key, int value) { int index = indexOfKey(key); if (index >= 0) { values[index] = value; } else { growIfNeeded(); keys[size] = key; values[size] = value; size++; } } /** * Returns the number of key-value mappings that this SparseIntArray * currently stores. */ public int size() { return size; } /** * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this * SparseLongArray stores. * * <p>The keys corresponding to indices in ascending order are guaranteed to * be in ascending order, e.g., <code>keyAt(0)</code> will return the * smallest key and <code>keyAt(size()-1)</code> will return the largest * key.</p> */ public long keyAt(int index) { if (index >= size) { throw new IndexOutOfBoundsException("n >= size()"); } else if(index < 0) { throw new IndexOutOfBoundsException("n < 0"); } return keys[index]; } /** * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this * SparseLongArray stores. * * <p>The values corresponding to indices in ascending order are guaranteed * to be associated with keys in ascending order, e.g., * <code>valueAt(0)</code> will return the value associated with the * smallest key and <code>valueAt(size()-1)</code> will return the value * associated with the largest key.</p> */ public int valueAt(int index) { if (index >= size) { throw new IndexOutOfBoundsException("n >= size()"); } else if(index < 0) { throw new IndexOutOfBoundsException("n < 0"); } return values[index]; } /** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative number if the specified * key is not mapped. */ public int indexOfKey(long key) { for(int i=0; i < size; i++) { if(keys[i] == key) { return i; } } return -1; } /** * Returns an index for which {@link #valueAt} would return the * specified key, or a negative number if no keys map to the * specified value. * Beware that this is a linear search, unlike lookups by key, * and that multiple keys can map to the same value and this will * find only one of them. */ public int indexOfValue(long value) { for (int i = 0; i < size; i++) { if (values[i] == value) { return i; } } return -1; } /** * Removes all key-value mappings from this SparseIntArray. */ public void clear() { keys = new long[10]; values = new int[10]; size = 0; } /** * Returns a copy of the values contained in this map. * * @return a copy of the values contained in this map */ public int[] values() { return Arrays.copyOf(values, size); } @Override public boolean equals(Object other) { if (other == this) { return true; } if (! (other instanceof LongIntMap)) { return false; } LongIntMap otherMap = (LongIntMap) other; if (size != otherMap.size) { return false; } for (int i = 0; i < size; i++) { if (keys[i] != otherMap.keys[i] || values[i] != otherMap.values[i]) { return false; } } return true; } @Override public int hashCode() { int hashCode = 1; for (int i = 0; i < size; i++) { long value = values[i]; hashCode = 31 * hashCode + (int)(value ^ (value >>> 32)); } return hashCode; } @Override public String toString() { if (size() <= 0) { return "LongLongMap{}"; } StringBuilder buffer = new StringBuilder(size * 28); buffer.append("LongLongMap{"); for (int i=0; i < size; i++) { if (i > 0) { buffer.append(", "); } long key = keyAt(i); buffer.append(key); buffer.append('='); long value = valueAt(i); buffer.append(value); } buffer.append('}'); return buffer.toString(); } }