--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/javax/swing/ArrayTable.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javax.swing;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/*
+ * Private storage mechanism for Action key-value pairs.
+ * In most cases this will be an array of alternating
+ * key-value pairs. As it grows larger it is scaled
+ * up to a Hashtable.
+ * <p>
+ * This does no synchronization, if you need thread safety synchronize on
+ * another object before calling this.
+ *
+ * @author Georges Saab
+ * @author Scott Violet
+ */
+class ArrayTable implements Cloneable {
+ // Our field for storage
+ private Object table = null;
+ private static final int ARRAY_BOUNDARY = 8;
+
+
+ /**
+ * Writes the passed in ArrayTable to the passed in ObjectOutputStream.
+ * The data is saved as an integer indicating how many key/value
+ * pairs are being archived, followed by the key/value pairs. If
+ * <code>table</code> is null, 0 will be written to <code>s</code>.
+ * <p>
+ * This is a convenience method that ActionMap/InputMap and
+ * AbstractAction use to avoid having the same code in each class.
+ */
+ static void writeArrayTable(ObjectOutputStream s, ArrayTable table) throws IOException {
+ Object keys[];
+
+ if (table == null || (keys = table.getKeys(null)) == null) {
+ s.writeInt(0);
+ }
+ else {
+ // Determine how many keys have Serializable values, when
+ // done all non-null values in keys identify the Serializable
+ // values.
+ int validCount = 0;
+
+ for (int counter = 0; counter < keys.length; counter++) {
+ Object key = keys[counter];
+
+ /* include in Serialization when both keys and values are Serializable */
+ if ( (key instanceof Serializable
+ && table.get(key) instanceof Serializable)
+ ||
+ /* include these only so that we get the appropriate exception below */
+ (key instanceof ClientPropertyKey
+ && ((ClientPropertyKey)key).getReportValueNotSerializable())) {
+
+ validCount++;
+ } else {
+ keys[counter] = null;
+ }
+ }
+ // Write ou the Serializable key/value pairs.
+ s.writeInt(validCount);
+ if (validCount > 0) {
+ for (Object key : keys) {
+ if (key != null) {
+ s.writeObject(key);
+ s.writeObject(table.get(key));
+ if (--validCount == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Put the key-value pair into storage
+ */
+ public void put(Object key, Object value){
+ if (table==null) {
+ table = new Object[] {key, value};
+ } else {
+ int size = size();
+ if (size < ARRAY_BOUNDARY) { // We are an array
+ if (containsKey(key)) {
+ Object[] tmp = (Object[])table;
+ for (int i = 0; i<tmp.length-1; i+=2) {
+ if (tmp[i].equals(key)) {
+ tmp[i+1]=value;
+ break;
+ }
+ }
+ } else {
+ Object[] array = (Object[])table;
+ int i = array.length;
+ Object[] tmp = new Object[i+2];
+ System.arraycopy(array, 0, tmp, 0, i);
+
+ tmp[i] = key;
+ tmp[i+1] = value;
+ table = tmp;
+ }
+ } else { // We are a hashtable
+ if ((size==ARRAY_BOUNDARY) && isArray()) {
+ grow();
+ }
+ @SuppressWarnings("unchecked")
+ Hashtable<Object,Object> tmp = (Hashtable<Object,Object>)table;
+ tmp.put(key, value);
+ }
+ }
+ }
+
+ /*
+ * Gets the value for key
+ */
+ public Object get(Object key) {
+ Object value = null;
+ if (table !=null) {
+ if (isArray()) {
+ Object[] array = (Object[])table;
+ for (int i = 0; i<array.length-1; i+=2) {
+ if (array[i].equals(key)) {
+ value = array[i+1];
+ break;
+ }
+ }
+ } else {
+ value = ((Hashtable)table).get(key);
+ }
+ }
+ return value;
+ }
+
+ /*
+ * Returns the number of pairs in storage
+ */
+ public int size() {
+ int size;
+ if (table==null)
+ return 0;
+ if (isArray()) {
+ size = ((Object[])table).length/2;
+ } else {
+ size = ((Hashtable)table).size();
+ }
+ return size;
+ }
+
+ /*
+ * Returns true if we have a value for the key
+ */
+ public boolean containsKey(Object key) {
+ boolean contains = false;
+ if (table !=null) {
+ if (isArray()) {
+ Object[] array = (Object[])table;
+ for (int i = 0; i<array.length-1; i+=2) {
+ if (array[i].equals(key)) {
+ contains = true;
+ break;
+ }
+ }
+ } else {
+ contains = ((Hashtable)table).containsKey(key);
+ }
+ }
+ return contains;
+ }
+
+ /*
+ * Removes the key and its value
+ * Returns the value for the pair removed
+ */
+ public Object remove(Object key){
+ Object value = null;
+ if (key==null) {
+ return null;
+ }
+ if (table !=null) {
+ if (isArray()){
+ // Is key on the list?
+ int index = -1;
+ Object[] array = (Object[])table;
+ for (int i = array.length-2; i>=0; i-=2) {
+ if (array[i].equals(key)) {
+ index = i;
+ value = array[i+1];
+ break;
+ }
+ }
+
+ // If so, remove it
+ if (index != -1) {
+ Object[] tmp = new Object[array.length-2];
+ // Copy the list up to index
+ System.arraycopy(array, 0, tmp, 0, index);
+ // Copy from two past the index, up to
+ // the end of tmp (which is two elements
+ // shorter than the old list)
+ if (index < tmp.length)
+ System.arraycopy(array, index+2, tmp, index,
+ tmp.length - index);
+ // set the listener array to the new array or null
+ table = (tmp.length == 0) ? null : tmp;
+ }
+ } else {
+ value = ((Hashtable)table).remove(key);
+ }
+ if (size()==ARRAY_BOUNDARY - 1 && !isArray()) {
+ shrink();
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Removes all the mappings.
+ */
+ public void clear() {
+ table = null;
+ }
+
+ /*
+ * Returns a clone of the <code>ArrayTable</code>.
+ */
+ public Object clone() {
+ ArrayTable newArrayTable = new ArrayTable();
+ if (isArray()) {
+ Object[] array = (Object[])table;
+ for (int i = 0 ;i < array.length-1 ; i+=2) {
+ newArrayTable.put(array[i], array[i+1]);
+ }
+ } else {
+ Hashtable<?,?> tmp = (Hashtable)table;
+ Enumeration<?> keys = tmp.keys();
+ while (keys.hasMoreElements()) {
+ Object o = keys.nextElement();
+ newArrayTable.put(o,tmp.get(o));
+ }
+ }
+ return newArrayTable;
+ }
+
+ /**
+ * Returns the keys of the table, or <code>null</code> if there
+ * are currently no bindings.
+ * @param keys array of keys
+ * @return an array of bindings
+ */
+ public Object[] getKeys(Object[] keys) {
+ if (table == null) {
+ return null;
+ }
+ if (isArray()) {
+ Object[] array = (Object[])table;
+ if (keys == null) {
+ keys = new Object[array.length / 2];
+ }
+ for (int i = 0, index = 0 ;i < array.length-1 ; i+=2,
+ index++) {
+ keys[index] = array[i];
+ }
+ } else {
+ Hashtable<?,?> tmp = (Hashtable)table;
+ Enumeration<?> enum_ = tmp.keys();
+ int counter = tmp.size();
+ if (keys == null) {
+ keys = new Object[counter];
+ }
+ while (counter > 0) {
+ keys[--counter] = enum_.nextElement();
+ }
+ }
+ return keys;
+ }
+
+ /*
+ * Returns true if the current storage mechanism is
+ * an array of alternating key-value pairs.
+ */
+ private boolean isArray(){
+ return (table instanceof Object[]);
+ }
+
+ /*
+ * Grows the storage from an array to a hashtable.
+ */
+ private void grow() {
+ Object[] array = (Object[])table;
+ Hashtable<Object, Object> tmp = new Hashtable<Object, Object>(array.length/2);
+ for (int i = 0; i<array.length; i+=2) {
+ tmp.put(array[i], array[i+1]);
+ }
+ table = tmp;
+ }
+
+ /*
+ * Shrinks the storage from a hashtable to an array.
+ */
+ private void shrink() {
+ Hashtable<?,?> tmp = (Hashtable)table;
+ Object[] array = new Object[tmp.size()*2];
+ Enumeration<?> keys = tmp.keys();
+ int j = 0;
+
+ while (keys.hasMoreElements()) {
+ Object o = keys.nextElement();
+ array[j] = o;
+ array[j+1] = tmp.get(o);
+ j+=2;
+ }
+ table = array;
+ }
+}