1 package jalview.ext.android;
4 * Copyright (C) 2006 The Android Open Source Project
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 * SparseShortArrays map shorts to shorts. Unlike a normal array of shorts,
20 * there can be gaps in the indices. It is intended to be more memory efficient
21 * than using a HashMap to map Shorts to Shorts, both because it avoids
22 * auto-boxing keys and values and its data structure doesn't rely on an extra
23 * entry object for each mapping.
26 * Note that this container keeps its mappings in an array data structure, using
27 * a binary search to find keys. The implementation is not intended to be
28 * appropriate for data structures that may contain large numbers of items. It
29 * is generally slower than a traditional HashMap, since lookups require a
30 * binary search and adds and removes require inserting and deleting entries in
31 * the array. For containers holding up to hundreds of items, the performance
32 * difference is not significant, less than 50%.
36 * It is possible to iterate over the items in this container using
37 * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
38 * <code>keyAt(int)</code> with ascending values of the index will return the
39 * keys in ascending order, or the values corresponding to the keys in ascending
40 * order in the case of <code>valueAt(int)<code>.
45 * Added to Jalview September 2016. A copy of SparseIntArray designed to store
46 * short values (to minimise space usage).
48 * Note that operations append, put, add throw ArithmeticException if either the
49 * key or the resulting value overflows the range of a short. Calling code
50 * should trap and handle this, for example by switching to using a
51 * SparseIntArray instead.
53 public class SparseShortArray implements Cloneable
55 private short[] mKeys;
57 private short[] mValues;
62 * Creates a new SparseShortArray containing no mappings.
64 public SparseShortArray()
70 * Creates a new SparseShortArray containing no mappings that will not require
71 * any additional memory allocation to store the specified number of mappings.
72 * If you supply an initial capacity of 0, the sparse array will be
73 * initialized with a light-weight representation not requiring any additional
76 public SparseShortArray(int initialCapacity)
78 if (initialCapacity == 0)
81 mValues = new short[0];
85 initialCapacity = idealShortArraySize(initialCapacity);
86 mKeys = new short[initialCapacity];
87 mValues = new short[initialCapacity];
93 public SparseShortArray clone()
95 SparseShortArray clone = null;
98 clone = (SparseShortArray) super.clone();
99 clone.mKeys = mKeys.clone();
100 clone.mValues = mValues.clone();
101 } catch (CloneNotSupportedException cnse)
109 * Gets the int mapped from the specified key, or <code>0</code> if no such
110 * mapping has been made.
112 public int get(int key)
118 * Gets the int mapped from the specified key, or the specified value if no
119 * such mapping has been made.
121 * @throws ArithmeticException
122 * if key is outside the range of a short value
124 public int get(int key, int valueIfKeyNotFound)
127 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
130 return valueIfKeyNotFound;
139 * Removes the mapping from the specified key, if there was any.
141 * @throws ArithmeticException
142 * if key is outside the range of a short value
144 public void delete(int key)
147 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
155 * Removes the mapping at the given index.
157 public void removeAt(int index)
159 System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
160 System.arraycopy(mValues, index + 1, mValues, index, mSize
166 * Adds a mapping from the specified key to the specified value, replacing the
167 * previous mapping from the specified key if there was one.
169 * @throws ArithmeticException
170 * if either argument is outside the range of a short value
172 public void put(int key, int value)
175 checkOverflow(value);
176 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
179 mValues[i] = (short) value;
184 if (mSize >= mKeys.length)
186 int n = idealShortArraySize(mSize + 1);
187 short[] nkeys = new short[n];
188 short[] nvalues = new short[n];
189 // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
190 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
191 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
197 // Log.e("SparseShortArray", "move " + (mSize - i));
198 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
199 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
201 mKeys[i] = (short) key;
202 mValues[i] = (short) value;
208 * Returns the number of key-value mappings that this SparseShortArray
217 * Given an index in the range <code>0...size()-1</code>, returns the key from
218 * the <code>index</code>th key-value mapping that this SparseShortArray
222 * The keys corresponding to indices in ascending order are guaranteed to be
223 * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
224 * key and <code>keyAt(size()-1)</code> will return the largest key.
227 public short keyAt(int index)
233 * Given an index in the range <code>0...size()-1</code>, returns the value
234 * from the <code>index</code>th key-value mapping that this SparseShortArray
238 * The values corresponding to indices in ascending order are guaranteed to be
239 * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
240 * return the value associated with the smallest key and
241 * <code>valueAt(size()-1)</code> will return the value associated with the
245 public short valueAt(int index)
247 return mValues[index];
251 * Returns the index for which {@link #keyAt} would return the specified key,
252 * or a negative number if the specified key is not mapped.
254 * @throws ArithmeticException
255 * if key is outside the range of a short value
257 public int indexOfKey(int key)
260 return ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
264 * Returns an index for which {@link #valueAt} would return the specified key,
265 * or a negative number if no keys map to the specified value. Beware that
266 * this is a linear search, unlike lookups by key, and that multiple keys can
267 * map to the same value and this will find only one of them.
269 public int indexOfValue(int value)
271 for (int i = 0; i < mSize; i++)
273 if (mValues[i] == value)
282 * Removes all key-value mappings from this SparseShortArray.
290 * Puts a key/value pair into the array, optimizing for the case where the key
291 * is greater than all existing keys in the array.
293 public void append(int key, int value)
295 if (mSize != 0 && key <= mKeys[mSize - 1])
301 if (pos >= mKeys.length)
303 int n = idealShortArraySize(pos + 1);
304 short[] nkeys = new short[n];
305 short[] nvalues = new short[n];
306 // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
307 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
308 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
313 checkOverflow(value);
314 mKeys[pos] = (short) key;
315 mValues[pos] = (short) value;
320 * Throws an exception if the value is outside the range of a short.
323 * @throws ArithmeticException
325 public static void checkOverflow(int value)
327 if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
329 throw new ArithmeticException(String.valueOf(value));
334 * Inlined here by copying from com.android.internal.util.ArrayUtils
339 public static int idealShortArraySize(int need)
341 return idealByteArraySize(need * 2) / 2;
345 * Inlined here by copying from com.android.internal.util.ArrayUtils
350 public static int idealByteArraySize(int need)
352 for (int i = 4; i < 32; i++)
354 if (need <= (1 << i) - 12)
356 return (1 << i) - 12;
367 * This implementation composes a string by iterating over its mappings.
370 public String toString()
376 StringBuilder buffer = new StringBuilder(mSize * 28);
378 for (int i = 0; i < mSize; i++)
387 int value = valueAt(i);
388 buffer.append(value);
391 return buffer.toString();
395 * Method (copied from put) added for Jalview to efficiently increment a key's
396 * value if present, else add it with the given value. This avoids a double
397 * binary search (once to get the value, again to put the updated value).
401 * @return the new value of the count for the key
402 * @throws ArithmeticException
403 * if key, or result of adding toAdd, is outside the range of a
406 public int add(int key, int toAdd)
408 int newValue = toAdd;
410 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
413 checkOverflow(toAdd + mValues[i]);
414 mValues[i] += (short) toAdd;
415 newValue = mValues[i];
419 checkOverflow(toAdd);
421 if (mSize >= mKeys.length)
423 int n = idealShortArraySize(mSize + 1);
424 short[] nkeys = new short[n];
425 short[] nvalues = new short[n];
426 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
427 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
433 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
434 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
436 mKeys[i] = (short) key;
437 mValues[i] = (short) toAdd;