Path: blob/master/src/java.desktop/share/classes/javax/swing/ArrayTable.java
41153 views
/*1* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package javax.swing;2526import java.io.IOException;27import java.io.ObjectOutputStream;28import java.io.Serializable;29import java.util.Enumeration;30import java.util.Hashtable;3132/*33* Private storage mechanism for Action key-value pairs.34* In most cases this will be an array of alternating35* key-value pairs. As it grows larger it is scaled36* up to a Hashtable.37* <p>38* This does no synchronization, if you need thread safety synchronize on39* another object before calling this.40*41* @author Georges Saab42* @author Scott Violet43*/44class ArrayTable implements Cloneable {45// Our field for storage46private Object table = null;47private static final int ARRAY_BOUNDARY = 8;484950/**51* Writes the passed in ArrayTable to the passed in ObjectOutputStream.52* The data is saved as an integer indicating how many key/value53* pairs are being archived, followed by the key/value pairs. If54* <code>table</code> is null, 0 will be written to <code>s</code>.55* <p>56* This is a convenience method that ActionMap/InputMap and57* AbstractAction use to avoid having the same code in each class.58*/59static void writeArrayTable(ObjectOutputStream s, ArrayTable table) throws IOException {60Object[] keys;6162if (table == null || (keys = table.getKeys(null)) == null) {63s.writeInt(0);64}65else {66// Determine how many keys have Serializable values, when67// done all non-null values in keys identify the Serializable68// values.69int validCount = 0;7071for (int counter = 0; counter < keys.length; counter++) {72Object key = keys[counter];7374/* include in Serialization when both keys and values are Serializable */75if ( (key instanceof Serializable76&& table.get(key) instanceof Serializable)77||78/* include these only so that we get the appropriate exception below */79(key instanceof ClientPropertyKey80&& ((ClientPropertyKey)key).getReportValueNotSerializable())) {8182validCount++;83} else {84keys[counter] = null;85}86}87// Write ou the Serializable key/value pairs.88s.writeInt(validCount);89if (validCount > 0) {90for (Object key : keys) {91if (key != null) {92s.writeObject(key);93s.writeObject(table.get(key));94if (--validCount == 0) {95break;96}97}98}99}100}101}102103104/*105* Put the key-value pair into storage106*/107public void put(Object key, Object value){108if (table==null) {109table = new Object[] {key, value};110} else {111int size = size();112if (size < ARRAY_BOUNDARY) { // We are an array113if (containsKey(key)) {114Object[] tmp = (Object[])table;115for (int i = 0; i<tmp.length-1; i+=2) {116if (tmp[i].equals(key)) {117tmp[i+1]=value;118break;119}120}121} else {122Object[] array = (Object[])table;123int i = array.length;124Object[] tmp = new Object[i+2];125System.arraycopy(array, 0, tmp, 0, i);126127tmp[i] = key;128tmp[i+1] = value;129table = tmp;130}131} else { // We are a hashtable132if ((size==ARRAY_BOUNDARY) && isArray()) {133grow();134}135@SuppressWarnings("unchecked")136Hashtable<Object,Object> tmp = (Hashtable<Object,Object>)table;137tmp.put(key, value);138}139}140}141142/*143* Gets the value for key144*/145public Object get(Object key) {146Object value = null;147if (table !=null) {148if (isArray()) {149Object[] array = (Object[])table;150for (int i = 0; i<array.length-1; i+=2) {151if (array[i].equals(key)) {152value = array[i+1];153break;154}155}156} else {157value = ((Hashtable)table).get(key);158}159}160return value;161}162163/*164* Returns the number of pairs in storage165*/166public int size() {167int size;168if (table==null)169return 0;170if (isArray()) {171size = ((Object[])table).length/2;172} else {173size = ((Hashtable)table).size();174}175return size;176}177178/*179* Returns true if we have a value for the key180*/181public boolean containsKey(Object key) {182boolean contains = false;183if (table !=null) {184if (isArray()) {185Object[] array = (Object[])table;186for (int i = 0; i<array.length-1; i+=2) {187if (array[i].equals(key)) {188contains = true;189break;190}191}192} else {193contains = ((Hashtable)table).containsKey(key);194}195}196return contains;197}198199/*200* Removes the key and its value201* Returns the value for the pair removed202*/203public Object remove(Object key){204Object value = null;205if (key==null) {206return null;207}208if (table !=null) {209if (isArray()){210// Is key on the list?211int index = -1;212Object[] array = (Object[])table;213for (int i = array.length-2; i>=0; i-=2) {214if (array[i].equals(key)) {215index = i;216value = array[i+1];217break;218}219}220221// If so, remove it222if (index != -1) {223Object[] tmp = new Object[array.length-2];224// Copy the list up to index225System.arraycopy(array, 0, tmp, 0, index);226// Copy from two past the index, up to227// the end of tmp (which is two elements228// shorter than the old list)229if (index < tmp.length)230System.arraycopy(array, index+2, tmp, index,231tmp.length - index);232// set the listener array to the new array or null233table = (tmp.length == 0) ? null : tmp;234}235} else {236value = ((Hashtable)table).remove(key);237}238if (size()==ARRAY_BOUNDARY - 1 && !isArray()) {239shrink();240}241}242return value;243}244245/**246* Removes all the mappings.247*/248public void clear() {249table = null;250}251252/*253* Returns a clone of the <code>ArrayTable</code>.254*/255public Object clone() {256ArrayTable newArrayTable = new ArrayTable();257if (table != null) {258if (isArray()) {259Object[] array = (Object[]) table;260for (int i = 0; i < array.length - 1; i += 2) {261newArrayTable.put(array[i], array[i + 1]);262}263} else {264Hashtable<?, ?> tmp = (Hashtable) table;265Enumeration<?> keys = tmp.keys();266while (keys.hasMoreElements()) {267Object o = keys.nextElement();268newArrayTable.put(o, tmp.get(o));269}270}271}272return newArrayTable;273}274275/**276* Returns the keys of the table, or <code>null</code> if there277* are currently no bindings.278* @param keys array of keys279* @return an array of bindings280*/281public Object[] getKeys(Object[] keys) {282if (table == null) {283return null;284}285if (isArray()) {286Object[] array = (Object[])table;287if (keys == null) {288keys = new Object[array.length / 2];289}290for (int i = 0, index = 0 ;i < array.length-1 ; i+=2,291index++) {292keys[index] = array[i];293}294} else {295Hashtable<?,?> tmp = (Hashtable)table;296Enumeration<?> enum_ = tmp.keys();297int counter = tmp.size();298if (keys == null) {299keys = new Object[counter];300}301while (counter > 0) {302keys[--counter] = enum_.nextElement();303}304}305return keys;306}307308/*309* Returns true if the current storage mechanism is310* an array of alternating key-value pairs.311*/312private boolean isArray(){313return (table instanceof Object[]);314}315316/*317* Grows the storage from an array to a hashtable.318*/319private void grow() {320Object[] array = (Object[])table;321Hashtable<Object, Object> tmp = new Hashtable<Object, Object>(array.length/2);322for (int i = 0; i<array.length; i+=2) {323tmp.put(array[i], array[i+1]);324}325table = tmp;326}327328/*329* Shrinks the storage from a hashtable to an array.330*/331private void shrink() {332Hashtable<?,?> tmp = (Hashtable)table;333Object[] array = new Object[tmp.size()*2];334Enumeration<?> keys = tmp.keys();335int j = 0;336337while (keys.hasMoreElements()) {338Object o = keys.nextElement();339array[j] = o;340array[j+1] = tmp.get(o);341j+=2;342}343table = array;344}345}346347348