1. /*
  2. * @(#)ArrayTable.java 1.4 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.io.IOException;
  9. import java.io.ObjectOutputStream;
  10. import java.io.Serializable;
  11. import java.util.Enumeration;
  12. import java.util.Hashtable;
  13. /*
  14. * Private storage mechanism for Action key-value pairs.
  15. * In most cases this will be an array of alternating
  16. * key-value pairs. As it grows larger it is scaled
  17. * up to a Hashtable.
  18. * <p>
  19. * This does no synchronization, if you need thread safety synchronize on
  20. * another object before calling this.
  21. *
  22. * @version 1.4 12/19/03
  23. * @author Georges Saab
  24. * @author Scott Violet
  25. */
  26. class ArrayTable implements Cloneable {
  27. // Our field for storage
  28. private Object table = null;
  29. private static final int ARRAY_BOUNDARY = 8;
  30. /**
  31. * Writes the passed in ArrayTable to the passed in ObjectOutputStream.
  32. * The data is saved as an integer indicating how many key/value
  33. * pairs are being archived, followed by the the key/value pairs. If
  34. * <code>table</code> is null, 0 will be written to <code>s</code>.
  35. * <p>
  36. * This is a convenience method that ActionMap/InputMap and
  37. * AbstractAction use to avoid having the same code in each class.
  38. */
  39. static void writeArrayTable(ObjectOutputStream s, ArrayTable table) throws IOException {
  40. Object keys[];
  41. if (table == null || (keys = table.getKeys(null)) == null) {
  42. s.writeInt(0);
  43. }
  44. else {
  45. // Determine how many keys have Serializable values, when
  46. // done all non-null values in keys identify the Serializable
  47. // values.
  48. int validCount = 0;
  49. for (int counter = 0; counter < keys.length; counter++) {
  50. if ((keys[counter] instanceof Serializable) &&
  51. (table.get(keys[counter]) instanceof Serializable)) {
  52. validCount++;
  53. }
  54. else {
  55. keys[counter] = null;
  56. }
  57. }
  58. // Write ou the Serializable key/value pairs.
  59. s.writeInt(validCount);
  60. if (validCount > 0) {
  61. for (int counter = 0; counter < keys.length; counter++) {
  62. if (keys[counter] != null) {
  63. s.writeObject(keys[counter]);
  64. s.writeObject(table.get(keys[counter]));
  65. if (--validCount == 0) {
  66. break;
  67. }
  68. }
  69. }
  70. }
  71. }
  72. }
  73. /*
  74. * Put the key-value pair into storage
  75. */
  76. public void put(Object key, Object value){
  77. if (table==null) {
  78. table = new Object[] {key, value};
  79. } else {
  80. int size = size();
  81. if (size < ARRAY_BOUNDARY) { // We are an array
  82. if (containsKey(key)) {
  83. Object[] tmp = (Object[])table;
  84. for (int i = 0; i<tmp.length-1; i+=2) {
  85. if (tmp[i].equals(key)) {
  86. tmp[i+1]=value;
  87. break;
  88. }
  89. }
  90. } else {
  91. Object[] array = (Object[])table;
  92. int i = array.length;
  93. Object[] tmp = new Object[i+2];
  94. System.arraycopy(array, 0, tmp, 0, i);
  95. tmp[i] = key;
  96. tmp[i+1] = value;
  97. table = tmp;
  98. }
  99. } else { // We are a hashtable
  100. if ((size==ARRAY_BOUNDARY) && isArray()) {
  101. grow();
  102. }
  103. ((Hashtable)table).put(key, value);
  104. }
  105. }
  106. }
  107. /*
  108. * Gets the value for key
  109. */
  110. public Object get(Object key) {
  111. Object value = null;
  112. if (table !=null) {
  113. if (isArray()) {
  114. Object[] array = (Object[])table;
  115. for (int i = 0; i<array.length-1; i+=2) {
  116. if (array[i].equals(key)) {
  117. value = array[i+1];
  118. break;
  119. }
  120. }
  121. } else {
  122. value = ((Hashtable)table).get(key);
  123. }
  124. }
  125. return value;
  126. }
  127. /*
  128. * Returns the number of pairs in storage
  129. */
  130. public int size() {
  131. int size;
  132. if (table==null)
  133. return 0;
  134. if (isArray()) {
  135. size = ((Object[])table).length2;
  136. } else {
  137. size = ((Hashtable)table).size();
  138. }
  139. return size;
  140. }
  141. /*
  142. * Returns true if we have a value for the key
  143. */
  144. public boolean containsKey(Object key) {
  145. boolean contains = false;
  146. if (table !=null) {
  147. if (isArray()) {
  148. Object[] array = (Object[])table;
  149. for (int i = 0; i<array.length-1; i+=2) {
  150. if (array[i].equals(key)) {
  151. contains = true;
  152. break;
  153. }
  154. }
  155. } else {
  156. contains = ((Hashtable)table).containsKey(key);
  157. }
  158. }
  159. return contains;
  160. }
  161. /*
  162. * Removes the key and its value
  163. * Returns the value for the pair removed
  164. */
  165. public Object remove(Object key){
  166. Object value = null;
  167. if (key==null) {
  168. return null;
  169. }
  170. if (table !=null) {
  171. if (isArray()){
  172. // Is key on the list?
  173. int index = -1;
  174. Object[] array = (Object[])table;
  175. for (int i = array.length-2; i>=0; i-=2) {
  176. if (array[i].equals(key)) {
  177. index = i;
  178. value = array[i+1];
  179. break;
  180. }
  181. }
  182. // If so, remove it
  183. if (index != -1) {
  184. Object[] tmp = new Object[array.length-2];
  185. // Copy the list up to index
  186. System.arraycopy(array, 0, tmp, 0, index);
  187. // Copy from two past the index, up to
  188. // the end of tmp (which is two elements
  189. // shorter than the old list)
  190. if (index < tmp.length)
  191. System.arraycopy(array, index+2, tmp, index,
  192. tmp.length - index);
  193. // set the listener array to the new array or null
  194. table = (tmp.length == 0) ? null : tmp;
  195. }
  196. } else {
  197. value = ((Hashtable)table).remove(key);
  198. }
  199. if (size()==ARRAY_BOUNDARY - 1 && !isArray()) {
  200. shrink();
  201. }
  202. }
  203. return value;
  204. }
  205. /**
  206. * Removes all the mappings.
  207. */
  208. public void clear() {
  209. table = null;
  210. }
  211. /*
  212. * Returns a clone of the <code>ArrayTable</code>.
  213. */
  214. public Object clone() {
  215. ArrayTable newArrayTable = new ArrayTable();
  216. if (isArray()) {
  217. Object[] array = (Object[])table;
  218. for (int i = 0 ;i < array.length-1 ; i+=2) {
  219. newArrayTable.put(array[i], array[i+1]);
  220. }
  221. } else {
  222. Hashtable tmp = (Hashtable)table;
  223. Enumeration keys = tmp.keys();
  224. while (keys.hasMoreElements()) {
  225. Object o = keys.nextElement();
  226. newArrayTable.put(o,tmp.get(o));
  227. }
  228. }
  229. return newArrayTable;
  230. }
  231. /**
  232. * Returns the keys of the table, or <code>null</code> if there
  233. * are currently no bindings.
  234. * @param keys array of keys
  235. * @return an array of bindings
  236. */
  237. public Object[] getKeys(Object[] keys) {
  238. if (table == null) {
  239. return null;
  240. }
  241. if (isArray()) {
  242. Object[] array = (Object[])table;
  243. if (keys == null) {
  244. keys = new Object[array.length / 2];
  245. }
  246. for (int i = 0, index = 0 ;i < array.length-1 ; i+=2,
  247. index++) {
  248. keys[index] = array[i];
  249. }
  250. } else {
  251. Hashtable tmp = (Hashtable)table;
  252. Enumeration enum_ = tmp.keys();
  253. int counter = tmp.size();
  254. if (keys == null) {
  255. keys = new Object[counter];
  256. }
  257. while (counter > 0) {
  258. keys[--counter] = enum_.nextElement();
  259. }
  260. }
  261. return keys;
  262. }
  263. /*
  264. * Returns true if the current storage mechanism is
  265. * an array of alternating key-value pairs.
  266. */
  267. private boolean isArray(){
  268. return (table instanceof Object[]);
  269. }
  270. /*
  271. * Grows the storage from an array to a hashtable.
  272. */
  273. private void grow() {
  274. Object[] array = (Object[])table;
  275. Hashtable tmp = new Hashtable(array.length2);
  276. for (int i = 0; i<array.length; i+=2) {
  277. tmp.put(array[i], array[i+1]);
  278. }
  279. table = tmp;
  280. }
  281. /*
  282. * Shrinks the storage from a hashtable to an array.
  283. */
  284. private void shrink() {
  285. Hashtable tmp = (Hashtable)table;
  286. Object[] array = new Object[tmp.size()*2];
  287. Enumeration keys = tmp.keys();
  288. int j = 0;
  289. while (keys.hasMoreElements()) {
  290. Object o = keys.nextElement();
  291. array[j] = o;
  292. array[j+1] = tmp.get(o);
  293. j+=2;
  294. }
  295. table = array;
  296. }
  297. }