com.google.gwt.coreext.client.IterableFastStringMap.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.coreext.client.IterableFastStringMap.java

Source

/*
 * Copyright 2007 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 com.google.gwt.coreext.client;

import com.google.gwt.core.client.JavaScriptObject;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Special-case Map implementation which imposes limits on the types of keys
 * that can be used in return for much faster speed. In specific, only strings
 * that could be added to a JavaScript object as keys are valid.
 * @param <T> generic type
 */
public class IterableFastStringMap<T> extends AbstractMap<String, T> {
    /**
     * interface that allows for iteration through Object Map.
     * @param <T>
     */
    public interface IterationCallBack<T> {
        void onIteration(String key, T obj);
    }

    private static class ImplMapEntry<T> implements Map.Entry<String, T> {

        private String key;

        private T value;

        ImplMapEntry(String key, T value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public boolean equals(Object a) {
            if (a instanceof Map.Entry<?, ?>) {
                Map.Entry<?, ?> s = (Map.Entry<?, ?>) a;
                if (equalsWithNullCheck(key, s.getKey()) && equalsWithNullCheck(value, s.getValue())) {
                    return true;
                }
            }
            return false;
        }

        // strip prefix from key
        public String getKey() {
            return key;
        }

        public T getValue() {
            return value;
        }

        @Override
        public int hashCode() {
            int keyHash = 0;
            int valueHash = 0;
            if (key != null) {
                keyHash = key.hashCode();
            }
            if (value != null) {
                valueHash = value.hashCode();
            }
            return keyHash ^ valueHash;
        }

        public T setValue(T object) {
            T old = value;
            value = object;
            return old;
        }

        private boolean equalsWithNullCheck(Object a, Object b) {
            if (a == b) {
                return true;
            } else if (a == null) {
                return false;
            } else {
                return a.equals(b);
            }
        }
    }

    /*
     * Accesses need to be prefixed with ':' to prevent conflict with built-in
     * JavaScript properties.
     */
    private JavaScriptObject map;

    public IterableFastStringMap() {
        init();
    }

    @Override
    public void clear() {
        init();
    }

    @Override
    public boolean containsKey(Object key) {
        return containsKey(keyMustBeString(key), map);
    }

    @Override
    public boolean containsValue(Object arg0) {
        return values().contains(arg0);
    }

    @Override
    public Set<Map.Entry<String, T>> entrySet() {
        return new AbstractSet<Map.Entry<String, T>>() {

            @Override
            public boolean contains(Object key) {
                Map.Entry<?, ?> s = (Map.Entry<?, ?>) key;
                Object value = get(s.getKey());
                if (value == null) {
                    return value == s.getValue();
                } else {
                    return value.equals(s.getValue());
                }
            }

            @Override
            public Iterator<Map.Entry<String, T>> iterator() {

                Iterator<Map.Entry<String, T>> custom = new Iterator<Map.Entry<String, T>>() {
                    Iterator<String> keys = keySet().iterator();

                    public boolean hasNext() {
                        return keys.hasNext();
                    }

                    public Map.Entry<String, T> next() {
                        String key = keys.next();
                        return new ImplMapEntry<T>(key, get(key));
                    }

                    public void remove() {
                        keys.remove();
                    }
                };
                return custom;
            }

            @Override
            public int size() {
                return IterableFastStringMap.this.size();
            }

        };
    }

    @Override
    public T get(Object key) {
        return get(keyMustBeString(key));
    }

    // Prepend ':' to avoid conflicts with built-in Object properties.
    public native T get(String key) /*-{
                                    var value
                                    = this.@com.google.gwt.coreext.client.IterableFastStringMap::map[':' + key];
                                    return (value == null) ? null : value;
                                    }-*/;

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    public native void iterate(IterationCallBack<T> cb) /*-{
                                                        var objMap = this.@com.google.gwt.coreext.client.IterableFastStringMap::map;
                                                            
                                                        for (var key in objMap) {
                                                        if (key.charAt(0) == ':') {
                                                        cb.@com.google.gwt.coreext.client.IterableFastStringMap.IterationCallBack::onIteration(Ljava/lang/String;Ljava/lang/Object;)(key,objMap[key]);
                                                        }
                                                        }
                                                        }-*/;

    @Override
    public Set<String> keySet() {
        return new AbstractSet<String>() {
            @Override
            public boolean contains(Object key) {
                return containsKey(key);
            }

            @Override
            public Iterator<String> iterator() {
                List<String> l = new ArrayList<String>();
                addAllKeysFromJavascriptObject(l, map);
                return l.iterator();
            }

            @Override
            public int size() {
                return IterableFastStringMap.this.size();
            }
        };
    }

    // Prepend ':' to avoid conflicts with built-in Object properties.
    @Override
    public native T put(String key, T widget) /*-{
                                              var previous
                                              = this.@com.google.gwt.coreext.client.IterableFastStringMap::map[':' + key];
                                              this.@com.google.gwt.coreext.client.IterableFastStringMap::map[':' + key] = widget;
                                              return (previous == null) ? null : previous;
                                              }-*/;

    @Override
    public void putAll(Map<? extends String, ? extends T> arg0) {
        for (Map.Entry<? extends String, ? extends T> entry : arg0.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public T remove(Object key) {
        return remove(keyMustBeString(key));
    }

    // only count keys with ':' prefix
    @Override
    public native int size() /*-{
                             var value = this.@com.google.gwt.coreext.client.IterableFastStringMap::map;
                             var count = 0;
                             for(var key in value) {
                             if (key.charAt(0) == ':') ++count;
                             }
                             return count;
                             }-*/;

    @Override
    public Collection<T> values() {
        List<T> values = new ArrayList<T>();
        addAllValuesFromJavascriptObject(values, map);
        return values;
    }

    // only count keys with ':' prefix
    private native void addAllKeysFromJavascriptObject(Collection<String> s,
            JavaScriptObject javaScriptObject) /*-{
                                               for(var key in javaScriptObject) {
                                               if (key.charAt(0) != ':') continue;
                                               s.@java.util.Collection::add(Ljava/lang/Object;)(key.substring(1));
                                               }
                                               }-*/;

    // only count keys with ':' prefix
    private native void addAllValuesFromJavascriptObject(Collection<T> s, JavaScriptObject javaScriptObject) /*-{
                                                                                                             for(var key in javaScriptObject) {
                                                                                                             if (key.charAt(0) != ':') continue;
                                                                                                             var value = javaScriptObject[key];
                                                                                                             s.@java.util.Collection::add(Ljava/lang/Object;)(value);
                                                                                                             }
                                                                                                             }-*/;

    // Prepend ':' to avoid conflicts with built-in Object properties.
    private native boolean containsKey(String key, JavaScriptObject obj)/*-{
                                                                        return obj[':' + key] !== undefined;
                                                                        }-*/;

    private native void init() /*-{
                               this.@com.google.gwt.coreext.client.IterableFastStringMap::map = [];
                               }-*/;

    private String keyMustBeString(Object key) {
        if (key instanceof String) {
            return (String) key;
        } else {
            throw new IllegalArgumentException(
                    this.getClass().getName() + " can only have Strings as keys, not" + key);
        }
    }

    // Prepend ':' to avoid conflicts with built-in Object properties.
    private native T remove(String key) /*-{
                                        var previous
                                        = this.@com.google.gwt.coreext.client.IterableFastStringMap::map[':' + key];
                                        delete this.@com.google.gwt.coreext.client.IterableFastStringMap::map[':' + key];
                                        return (previous == null) ? null : previous;
                                        }-*/;
}