2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.android;
24 * Copyright (C) 2006 The Android Open Source Project
26 * Licensed under the Apache License, Version 2.0 (the "License");
27 * you may not use this file except in compliance with the License.
28 * You may obtain a copy of the License at
30 * http://www.apache.org/licenses/LICENSE-2.0
32 * Unless required by applicable law or agreed to in writing, software
33 * distributed under the License is distributed on an "AS IS" BASIS,
34 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 * See the License for the specific language governing permissions and
36 * limitations under the License.
39 * SparseShortArrays map shorts to shorts. Unlike a normal array of shorts,
40 * there can be gaps in the indices. It is intended to be more memory efficient
41 * than using a HashMap to map Shorts to Shorts, both because it avoids
42 * auto-boxing keys and values and its data structure doesn't rely on an extra
43 * entry object for each mapping.
46 * Note that this container keeps its mappings in an array data structure, using
47 * a binary search to find keys. The implementation is not intended to be
48 * appropriate for data structures that may contain large numbers of items. It
49 * is generally slower than a traditional HashMap, since lookups require a
50 * binary search and adds and removes require inserting and deleting entries in
51 * the array. For containers holding up to hundreds of items, the performance
52 * difference is not significant, less than 50%.
56 * It is possible to iterate over the items in this container using
57 * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
58 * <code>keyAt(int)</code> with ascending values of the index will return the
59 * keys in ascending order, or the values corresponding to the keys in ascending
60 * order in the case of <code>valueAt(int)<code>.
65 * Added to Jalview September 2016. A copy of SparseIntArray designed to store
66 * short values (to minimise space usage).
68 * Note that operations append, put, add throw ArithmeticException if either the
69 * key or the resulting value overflows the range of a short. Calling code
70 * should trap and handle this, for example by switching to using a
71 * SparseIntArray instead.
73 public class SparseShortArray implements Cloneable
75 private short[] mKeys;
77 private short[] mValues;
82 * Creates a new SparseShortArray containing no mappings.
84 public SparseShortArray()
90 * Creates a new SparseShortArray containing no mappings that will not require
91 * any additional memory allocation to store the specified number of mappings.
92 * If you supply an initial capacity of 0, the sparse array will be
93 * initialized with a light-weight representation not requiring any additional
96 public SparseShortArray(int initialCapacity)
98 if (initialCapacity == 0)
100 mKeys = new short[0];
101 mValues = new short[0];
105 initialCapacity = idealShortArraySize(initialCapacity);
106 mKeys = new short[initialCapacity];
107 mValues = new short[initialCapacity];
113 public SparseShortArray clone()
115 SparseShortArray clone = null;
118 clone = (SparseShortArray) super.clone();
119 clone.mKeys = mKeys.clone();
120 clone.mValues = mValues.clone();
121 } catch (CloneNotSupportedException cnse)
129 * Gets the int mapped from the specified key, or <code>0</code> if no such
130 * mapping has been made.
132 public int get(int key)
138 * Gets the int mapped from the specified key, or the specified value if no
139 * such mapping has been made.
141 * @throws ArithmeticException
142 * if key is outside the range of a short value
144 public int get(int key, int valueIfKeyNotFound)
147 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
150 return valueIfKeyNotFound;
159 * Removes the mapping from the specified key, if there was any.
161 * @throws ArithmeticException
162 * if key is outside the range of a short value
164 public void delete(int key)
167 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
175 * Removes the mapping at the given index.
177 public void removeAt(int index)
179 System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
180 System.arraycopy(mValues, index + 1, mValues, index, mSize
186 * Adds a mapping from the specified key to the specified value, replacing the
187 * previous mapping from the specified key if there was one.
189 * @throws ArithmeticException
190 * if either argument is outside the range of a short value
192 public void put(int key, int value)
195 checkOverflow(value);
196 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
199 mValues[i] = (short) value;
204 if (mSize >= mKeys.length)
206 int n = idealShortArraySize(mSize + 1);
207 short[] nkeys = new short[n];
208 short[] nvalues = new short[n];
209 // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
210 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
211 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
217 // Log.e("SparseShortArray", "move " + (mSize - i));
218 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
219 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
221 mKeys[i] = (short) key;
222 mValues[i] = (short) value;
228 * Returns the number of key-value mappings that this SparseShortArray
237 * Given an index in the range <code>0...size()-1</code>, returns the key from
238 * the <code>index</code>th key-value mapping that this SparseShortArray
242 * The keys corresponding to indices in ascending order are guaranteed to be
243 * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
244 * key and <code>keyAt(size()-1)</code> will return the largest key.
247 public short keyAt(int index)
253 * Given an index in the range <code>0...size()-1</code>, returns the value
254 * from the <code>index</code>th key-value mapping that this SparseShortArray
258 * The values corresponding to indices in ascending order are guaranteed to be
259 * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
260 * return the value associated with the smallest key and
261 * <code>valueAt(size()-1)</code> will return the value associated with the
265 public short valueAt(int index)
267 return mValues[index];
271 * Returns the index for which {@link #keyAt} would return the specified key,
272 * or a negative number if the specified key is not mapped.
274 * @throws ArithmeticException
275 * if key is outside the range of a short value
277 public int indexOfKey(int key)
280 return ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
284 * Returns an index for which {@link #valueAt} would return the specified key,
285 * or a negative number if no keys map to the specified value. Beware that
286 * this is a linear search, unlike lookups by key, and that multiple keys can
287 * map to the same value and this will find only one of them.
289 public int indexOfValue(int value)
291 for (int i = 0; i < mSize; i++)
293 if (mValues[i] == value)
302 * Removes all key-value mappings from this SparseShortArray.
310 * Puts a key/value pair into the array, optimizing for the case where the key
311 * is greater than all existing keys in the array.
313 public void append(int key, int value)
315 if (mSize != 0 && key <= mKeys[mSize - 1])
321 if (pos >= mKeys.length)
323 int n = idealShortArraySize(pos + 1);
324 short[] nkeys = new short[n];
325 short[] nvalues = new short[n];
326 // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
327 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
328 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
333 checkOverflow(value);
334 mKeys[pos] = (short) key;
335 mValues[pos] = (short) value;
340 * Throws an exception if the value is outside the range of a short.
343 * @throws ArithmeticException
345 public static void checkOverflow(int value)
347 if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
349 throw new ArithmeticException(String.valueOf(value));
354 * Inlined here by copying from com.android.internal.util.ArrayUtils
359 public static int idealShortArraySize(int need)
361 return idealByteArraySize(need * 2) / 2;
365 * Inlined here by copying from com.android.internal.util.ArrayUtils
370 public static int idealByteArraySize(int need)
372 for (int i = 4; i < 32; i++)
374 if (need <= (1 << i) - 12)
376 return (1 << i) - 12;
387 * This implementation composes a string by iterating over its mappings.
390 public String toString()
396 StringBuilder buffer = new StringBuilder(mSize * 28);
398 for (int i = 0; i < mSize; i++)
407 int value = valueAt(i);
408 buffer.append(value);
411 return buffer.toString();
415 * Method (copied from put) added for Jalview to efficiently increment a key's
416 * value if present, else add it with the given value. This avoids a double
417 * binary search (once to get the value, again to put the updated value).
421 * @return the new value of the count for the key
422 * @throws ArithmeticException
423 * if key, or result of adding toAdd, is outside the range of a
426 public int add(int key, int toAdd)
428 int newValue = toAdd;
430 int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
433 checkOverflow(toAdd + mValues[i]);
434 mValues[i] += (short) toAdd;
435 newValue = mValues[i];
439 checkOverflow(toAdd);
441 if (mSize >= mKeys.length)
443 int n = idealShortArraySize(mSize + 1);
444 short[] nkeys = new short[n];
445 short[] nvalues = new short[n];
446 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
447 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
453 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
454 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
456 mKeys[i] = (short) key;
457 mValues[i] = (short) toAdd;