src/java.desktop/share/classes/javax/swing/ArrayTable.java
changeset 47216 71c04702a3d5
parent 28059 e576535359cc
child 52248 2e330da7cbf4
--- /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;
+    }
+}