1package org.bouncycastle.asn1; 2 3import java.util.Enumeration; 4import java.util.ConcurrentModificationException; 5 6// BEGIN android-note 7/* 8 * This is a new class that was synthesized from the observed 9 * requirement for a lookup table that preserves order. Since in 10 * practice the element count is typically very low, we just use a 11 * flat list rather than doing any hashing / bucketing. 12 */ 13// END android-note 14 15/** 16 * Ordered lookup table. Instances of this class will keep up to four 17 * key-value pairs directly, resorting to an external collection only 18 * if more elements than that need to be stored. 19 */ 20public final class OrderedTable { 21 /** null-ok; key #0 */ 22 private DERObjectIdentifier key0; 23 24 /** null-ok; key #1 */ 25 private DERObjectIdentifier key1; 26 27 /** null-ok; key #2 */ 28 private DERObjectIdentifier key2; 29 30 /** null-ok; key #3 */ 31 private DERObjectIdentifier key3; 32 33 /** null-ok; value #0 */ 34 private Object value0; 35 36 /** null-ok; value #1 */ 37 private Object value1; 38 39 /** null-ok; value #2 */ 40 private Object value2; 41 42 /** null-ok; value #3 */ 43 private Object value3; 44 45 /** 46 * null-ok; array of additional keys and values, alternating 47 * key then value, etc. 48 */ 49 private Object[] rest; 50 51 /** >= 0; number of elements in the list */ 52 private int size; 53 54 // Note: Default public constructor. 55 56 /** 57 * Adds an element. 58 * 59 * @param key non-null; the key 60 * @param value non-null; the value 61 */ 62 public void add(DERObjectIdentifier key, Object value) { 63 if (key == null) { 64 throw new NullPointerException("key == null"); 65 } 66 67 if (value == null) { 68 throw new NullPointerException("value == null"); 69 } 70 71 int sz = size; 72 73 switch (sz) { 74 case 0: { 75 key0 = key; 76 value0 = value; 77 break; 78 } 79 case 1: { 80 key1 = key; 81 value1 = value; 82 break; 83 } 84 case 2: { 85 key2 = key; 86 value2 = value; 87 break; 88 } 89 case 3: { 90 key3 = key; 91 value3 = value; 92 break; 93 } 94 case 4: { 95 // Do initial allocation of rest. 96 rest = new Object[10]; 97 rest[0] = key; 98 rest[1] = value; 99 break; 100 } 101 default: { 102 int index = (sz - 4) * 2; 103 int index1 = index + 1; 104 if (index1 >= rest.length) { 105 // Grow rest. 106 Object[] newRest = new Object[index1 * 2 + 10]; 107 System.arraycopy(rest, 0, newRest, 0, rest.length); 108 rest = newRest; 109 } 110 rest[index] = key; 111 rest[index1] = value; 112 break; 113 } 114 } 115 116 size = sz + 1; 117 } 118 119 /** 120 * Gets the number of elements in this instance. 121 */ 122 public int size() { 123 return size; 124 } 125 126 /** 127 * Look up the given key, returning the associated value if found. 128 * 129 * @param key non-null; the key to look up 130 * @return null-ok; the associated value 131 */ 132 public Object get(DERObjectIdentifier key) { 133 int keyHash = key.hashCode(); 134 int sz = size; 135 136 for (int i = 0; i < size; i++) { 137 DERObjectIdentifier probe = getKey(i); 138 if ((probe.hashCode() == keyHash) && 139 probe.equals(key)) { 140 return getValue(i); 141 } 142 } 143 144 return null; 145 } 146 147 /** 148 * Gets the nth key. 149 * 150 * @param n index 151 * @return non-null; the nth key 152 */ 153 public DERObjectIdentifier getKey(int n) { 154 if ((n < 0) || (n >= size)) { 155 throw new IndexOutOfBoundsException(Integer.toString(n)); 156 } 157 158 switch (n) { 159 case 0: return key0; 160 case 1: return key1; 161 case 2: return key2; 162 case 3: return key3; 163 default: return (DERObjectIdentifier) rest[(n - 4) * 2]; 164 } 165 } 166 167 /** 168 * Gets the nth value. 169 * 170 * @param n index 171 * @return non-null; the nth value 172 */ 173 public Object getValue(int n) { 174 if ((n < 0) || (n >= size)) { 175 throw new IndexOutOfBoundsException(Integer.toString(n)); 176 } 177 178 switch (n) { 179 case 0: return value0; 180 case 1: return value1; 181 case 2: return value2; 182 case 3: return value3; 183 default: return rest[((n - 4) * 2) + 1]; 184 } 185 } 186 187 /** 188 * Gets an enumeration of the keys, in order. 189 * 190 * @return non-null; an enumeration of the keys 191 */ 192 public Enumeration getKeys() { 193 return new KeyEnumeration(); 194 } 195 196 /** 197 * Associated enumeration class. 198 */ 199 private class KeyEnumeration implements Enumeration { 200 /** original size; used for modification detection */ 201 private final int origSize = size; 202 203 /** >= 0; current cursor */ 204 private int at = 0; 205 206 /** {@inheritDoc} */ 207 public boolean hasMoreElements() { 208 if (size != origSize) { 209 throw new ConcurrentModificationException(); 210 } 211 212 return at < origSize; 213 } 214 215 /** {@inheritDoc} */ 216 public Object nextElement() { 217 if (size != origSize) { 218 throw new ConcurrentModificationException(); 219 } 220 221 return getKey(at++); 222 } 223 } 224} 225