JAL-2325 tidy up release notes
[jalview.git] / src / jalview / util / SparseCount.java
1 package jalview.util;
2
3 import jalview.ext.android.SparseIntArray;
4 import jalview.ext.android.SparseShortArray;
5
6 /**
7  * A class to count occurrences of characters with minimal memory footprint.
8  * Sparse arrays of short values are used to hold the counts, with automatic
9  * promotion to arrays of int if any count exceeds the maximum value for a
10  * short.
11  * 
12  * @author gmcarstairs
13  *
14  */
15 public class SparseCount
16 {
17   private static final int DEFAULT_PROFILE_SIZE = 2;
18
19   /*
20    * array of keys (chars) and values (counts)
21    * held either as shorts or (if shorts overflow) as ints 
22    */
23   private SparseShortArray shortProfile;
24
25   private SparseIntArray intProfile;
26
27   /*
28    * flag is set true after short overflow occurs
29    */
30   private boolean useInts;
31
32   /**
33    * Constructor which initially creates a new sparse array of short values to
34    * hold counts.
35    * 
36    * @param profileSize
37    */
38   public SparseCount(int profileSize)
39   {
40     this.shortProfile = new SparseShortArray(profileSize);
41   }
42
43   /**
44    * Constructor which allocates an initial count array for only two distinct
45    * values (the array will grow if needed)
46    */
47   public SparseCount()
48   {
49     this(DEFAULT_PROFILE_SIZE);
50   }
51
52   /**
53    * Adds the given value for the given key (or sets the initial value), and
54    * returns the new value
55    * 
56    * @param key
57    * @param value
58    */
59   public int add(int key, int value)
60   {
61     int newValue = 0;
62     if (useInts)
63     {
64       newValue = intProfile.add(key, value);
65     }
66     else
67     {
68       try {
69         newValue = shortProfile.add(key, value);
70       } catch (ArithmeticException e) {
71         handleOverflow();
72         newValue = intProfile.add(key, value);
73       }
74     }
75     return newValue;
76   }
77
78   /**
79    * Switch from counting shorts to counting ints
80    */
81   synchronized void handleOverflow()
82   {
83     int size = shortProfile.size();
84     intProfile = new SparseIntArray(size);
85     for (int i = 0; i < size; i++)
86     {
87       short key = shortProfile.keyAt(i);
88       short value = shortProfile.valueAt(i);
89       intProfile.put(key, value);
90     }
91     shortProfile = null;
92     useInts = true;
93   }
94
95   /**
96    * Returns the size of the profile (number of distinct items counted)
97    * 
98    * @return
99    */
100   public int size()
101   {
102     return useInts ? intProfile.size() : shortProfile.size();
103   }
104
105   /**
106    * Returns the value for the key (zero if no such key)
107    * 
108    * @param key
109    * @return
110    */
111   public int get(int key)
112   {
113     return useInts ? intProfile.get(key) : shortProfile.get(key);
114   }
115
116   /**
117    * Sets the value for the given key
118    * 
119    * @param key
120    * @param value
121    */
122   public void put(int key, int value)
123   {
124     if (useInts)
125     {
126       intProfile.put(key, value);
127     }
128     else
129     {
130       shortProfile.put(key, value);
131     }
132   }
133
134   public int keyAt(int k)
135   {
136     return useInts ? intProfile.keyAt(k) : shortProfile.keyAt(k);
137   }
138
139   public int valueAt(int k)
140   {
141     return useInts ? intProfile.valueAt(k) : shortProfile.valueAt(k);
142   }
143
144   /**
145    * Answers true if this object wraps arrays of int values, false if using
146    * short values
147    * 
148    * @return
149    */
150   boolean isUsingInt()
151   {
152     return useInts;
153   }
154 }