com.google.gwt.emul.java.util.AbstractHashMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vaadin-client Show documentation
Show all versions of vaadin-client Show documentation
Vaadin is a web application framework for Rich Internet Applications (RIA).
Vaadin enables easy development and maintenance of fast and
secure rich web
applications with a stunning look and feel and a wide browser support.
It features a server-side architecture with the majority of the logic
running
on the server. Ajax technology is used at the browser-side to ensure a
rich
and interactive user experience.
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package java.util;
import static com.google.gwt.core.shared.impl.InternalPreconditions.checkArgument;
import static com.google.gwt.core.shared.impl.InternalPreconditions.checkElement;
import static com.google.gwt.core.shared.impl.InternalPreconditions.checkState;
import static java.util.ConcurrentModificationDetector.checkStructuralChange;
import static java.util.ConcurrentModificationDetector.recordLastKnownStructure;
import static java.util.ConcurrentModificationDetector.structureChanged;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.impl.SpecializeMethod;
/**
* Implementation of Map interface based on a hash table. [Sun
* docs]
*
* @param key type
* @param value type
*/
abstract class AbstractHashMap extends AbstractMap {
private final class EntrySet extends AbstractSet> {
@Override
public void clear() {
AbstractHashMap.this.clear();
}
@Override
public boolean contains(Object o) {
if (o instanceof Map.Entry) {
return containsEntry((Map.Entry, ?>) o);
}
return false;
}
@Override
public Iterator> iterator() {
return new EntrySetIterator();
}
@Override
public boolean remove(Object entry) {
if (contains(entry)) {
Object key = ((Map.Entry, ?>) entry).getKey();
AbstractHashMap.this.remove(key);
return true;
}
return false;
}
@Override
public int size() {
return AbstractHashMap.this.size();
}
}
/**
* Iterator for EntrySet
.
*/
private final class EntrySetIterator implements Iterator> {
private Iterator> stringMapEntries = stringMap.entries();
private Iterator> current = stringMapEntries;
private Iterator> last;
public EntrySetIterator() {
recordLastKnownStructure(AbstractHashMap.this, this);
}
@Override
public boolean hasNext() {
if (current.hasNext()) {
return true;
}
if (current != stringMapEntries) {
return false;
}
current = hashCodeMap.entries();
return current.hasNext();
}
@Override
public Entry next() {
checkStructuralChange(AbstractHashMap.this, this);
checkElement(hasNext());
last = current;
return current.next();
}
@Override
public void remove() {
checkState(last != null);
checkStructuralChange(AbstractHashMap.this, this);
last.remove();
last = null;
recordLastKnownStructure(AbstractHashMap.this, this);
}
}
/**
* A map of integral hashCodes onto entries.
*/
private transient InternalJsHashCodeMap hashCodeMap;
/**
* A map of Strings onto values.
*/
private transient InternalJsStringMap stringMap;
private int size;
public AbstractHashMap() {
reset();
}
public AbstractHashMap(int ignored) {
// This implementation of HashMap has no need of initial capacities.
this(ignored, 0);
}
public AbstractHashMap(int ignored, float alsoIgnored) {
// This implementation of HashMap has no need of load factors or capacities.
checkArgument(ignored >= 0, "Negative initial capacity");
checkArgument(alsoIgnored >= 0, "Non-positive load factor");
reset();
}
public AbstractHashMap(Map extends K, ? extends V> toBeCopied) {
reset();
this.putAll(toBeCopied);
}
@Override
public void clear() {
reset();
}
private void reset() {
InternalJsMapFactory factory = GWT.create(InternalJsMapFactory.class);
hashCodeMap = factory.createJsHashCodeMap();
hashCodeMap.host = this;
stringMap = factory.createJsStringMap();
stringMap.host = this;
size = 0;
structureChanged(this);
}
@SpecializeMethod(params = {String.class}, target = "hasStringValue")
@Override
public boolean containsKey(Object key) {
return key instanceof String ? hasStringValue(unsafeCast(key)) : hasHashValue(key);
}
@Override
public boolean containsValue(Object value) {
return stringMap.containsValue(value) || hashCodeMap.containsValue(value);
}
@Override
public Set> entrySet() {
return new EntrySet();
}
@SpecializeMethod(params = {String.class}, target = "getStringValue")
@Override
public V get(Object key) {
return key instanceof String ? getStringValue(unsafeCast(key)) : getHashValue(key);
}
@SpecializeMethod(params = {String.class, Object.class}, target = "putStringValue")
@Override
public V put(K key, V value) {
return key instanceof String ? putStringValue(unsafeCast(key), value) : putHashValue(key, value);
}
@SpecializeMethod(params = {String.class}, target = "removeStringValue")
@Override
public V remove(Object key) {
return key instanceof String ? removeStringValue(unsafeCast(key)) : removeHashValue(key);
}
@Override
public int size() {
return size;
}
void elementRemoved() {
size--;
structureChanged(this);
}
void elementAdded() {
size++;
structureChanged(this);
}
/**
* Subclasses must override to return a whether or not two keys or values are
* equal.
*/
abstract boolean equals(Object value1, Object value2);
/**
* Subclasses must override to return a hash code for a given key. The key is
* guaranteed to be non-null and not a String.
*/
abstract int getHashCode(Object key);
/**
* Returns the Map.Entry whose key is Object equal to key
,
* provided that key
's hash code is hashCode
;
* or null
if no such Map.Entry exists at the specified
* hashCode.
*/
private V getHashValue(Object key) {
return getEntryValueOrNull(hashCodeMap.getEntry(key));
}
/**
* Returns the value for the given key in the stringMap. Returns
* null
if the specified key does not exist.
*/
protected V getStringValue(String key) {
return key == null ? getHashValue(null) : stringMap.get(key);
}
/**
* Returns true if the a key exists in the hashCodeMap that is Object equal to
* key
, provided that key
's hash code is
* hashCode
.
*/
private boolean hasHashValue(Object key) {
return hashCodeMap.getEntry(key) != null;
}
/**
* Returns true if the given key exists in the stringMap.
*/
protected boolean hasStringValue(String key) {
return key == null ? hasHashValue(null) : stringMap.contains(key);
}
/**
* Sets the specified key to the specified value in the hashCodeMap. Returns
* the value previously at that key. Returns null
if the
* specified key did not exist.
*/
private V putHashValue(K key, V value) {
return hashCodeMap.put(key, value);
}
/**
* Sets the specified key to the specified value in the stringMap. Returns the
* value previously at that key. Returns null
if the specified
* key did not exist.
*/
protected V putStringValue(String key, V value) {
return key == null ? putHashValue(null, value) : stringMap.put(key, value);
}
/**
* Removes the pair whose key is Object equal to key
from
* hashCodeMap
, provided that key
's hash code
* is hashCode
. Returns the value that was associated with the
* removed key, or null if no such key existed.
*/
private V removeHashValue(Object key) {
return hashCodeMap.remove(key);
}
/**
* Removes the specified key from the stringMap and returns the value that was
* previously there. Returns null
if the specified key does not
* exist.
*/
protected V removeStringValue(String key) {
return key == null ? removeHashValue(null) : stringMap.remove(key);
}
// TODO(goktug): replace unsafeCast with a real cast when the compiler can optimize it.
static native String unsafeCast(Object string) /*-{
return string;
}-*/;
}