view dwtx/core/internal/jobs/ObjectMap.d @ 122:9d0585bcb7aa

Add core.jobs package
author Frank Benoit <benoit@tionex.de>
date Tue, 12 Aug 2008 02:34:21 +0200
parents
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 * Port to the D programming language:
 *     Frank Benoit <benoit@tionex.de>
 *******************************************************************************/
module dwtx.core.internal.jobs.ObjectMap;

import dwt.dwthelper.utils;
import dwtx.dwtxhelper.Collection;
import dwtx.core.internal.jobs.StringPool;

/**
 * A specialized map implementation that is optimized for a small set of object
 * keys.
 *
 * Implemented as a single array that alternates keys and values.
 *
 * Note: This class is copied from dwtx.core.resources
 */
public class ObjectMap : Map {
    // 8 attribute keys, 8 attribute values
    protected static const int DEFAULT_SIZE = 16;
    protected static const int GROW_SIZE = 10;
    protected int count = 0;
    protected Object[] elements = null;

    /**
     * Creates a new object map.
     *
     * @param initialCapacity
     *                  The initial number of elements that will fit in the map.
     */
    public this(int initialCapacity) {
        if (initialCapacity > 0)
            elements = new Object[Math.max(initialCapacity * 2, 0)];
    }

    /**
     * Creates a new object map of the same size as the given map and populate
     * it with the key/attribute pairs found in the map.
     *
     * @param map
     *                  The entries in the given map will be added to the new map.
     */
    public this(Map map) {
        this(map.size());
        putAll(map);
    }

    /**
     * @see Map#clear()
     */
    public void clear() {
        elements = null;
        count = 0;
    }

    /**
     * @see java.lang.Object#clone()
     */
    public Object clone() {
        return new ObjectMap(this);
    }

    /**
     * @see Map#containsKey(java.lang.Object)
     */
    public bool containsKey(Object key) {
        if (elements is null || count is 0)
            return false;
        for (int i = 0; i < elements.length; i = i + 2)
            if (elements[i] !is null && elements[i].opEquals(key))
                return true;
        return false;
    }
    public bool containsKey(String key) {
        return containsKey(stringcast(key));
    }
    /**
     * @see Map#containsValue(java.lang.Object)
     */
    public bool containsValue(Object value) {
        if (elements is null || count is 0)
            return false;
        for (int i = 1; i < elements.length; i = i + 2)
            if (elements[i] !is null && elements[i].opEquals(value))
                return true;
        return false;
    }

    /**
     * @see Map#entrySet()
     *
     * Note: This implementation does not conform properly to the
     * specification in the Map interface. The returned collection will not
     * be bound to this map and will not remain in sync with this map.
     */
    public Set entrySet() {
        return count is 0 ? Collections.EMPTY_SET : toHashMap().entrySet();
    }

    /**
     * @see Object#equals(java.lang.Object)
     */
    public override int opEquals(Object o) {
        if (!(cast(Map)o ))
            return false;
        Map other = cast(Map) o;
        //must be same size
        if (count !is other.size())
            return false;
        //keysets must be equal
        if (!(cast(Object)keySet()).opEquals(cast(Object)other.keySet()))
            return false;
        //values for each key must be equal
        for (int i = 0; i < elements.length; i = i + 2) {
            if (elements[i] !is null && (!elements[i + 1].opEquals(other.get(elements[i]))))
                return false;
        }
        return true;
    }

    /**
     * @see Map#get(java.lang.Object)
     */
    public Object get(Object key) {
        if (elements is null || count is 0)
            return null;
        for (int i = 0; i < elements.length; i = i + 2)
            if (elements[i] !is null && elements[i].opEquals(key))
                return elements[i + 1];
        return null;
    }
    public Object get(String key) {
        return get(stringcast(key));
    }

    /**
     * The capacity of the map has been exceeded, grow the array by GROW_SIZE to
     * accomodate more entries.
     */
    protected void grow() {
        Object[] expanded = new Object[elements.length + GROW_SIZE];
        System.arraycopy(elements, 0, expanded, 0, elements.length);
        elements = expanded;
    }

    /**
     * @see Object#hashCode()
     */
    public override hash_t toHash() {
        int hash = 0;
        for (int i = 0; i < elements.length; i = i + 2) {
            if (elements[i] !is null) {
                hash += elements[i].toHash();
            }
        }
        return hash;
    }

    /**
     * @see Map#isEmpty()
     */
    public bool isEmpty() {
        return count is 0;
    }

    /**
     * Returns all keys in this table as an array.
     */
    public String[] keys() {
        String[] result = new String[count];
        int next = 0;
        for (int i = 0; i < elements.length; i = i + 2)
            if (elements[i] !is null)
                result[next++] = stringcast( elements[i] );
        return result;
    }

    /**
     * @see Map#keySet()
     *
     * Note: This implementation does not conform properly to the
     * specification in the Map interface. The returned collection will not
     * be bound to this map and will not remain in sync with this map.
     */
    public Set keySet() {
        Set result = new HashSet(size());
        for (int i = 0; i < elements.length; i = i + 2) {
            if (elements[i] !is null) {
                result.add(elements[i]);
            }
        }
        return result;
    }

    /**
     * @see Map#put(java.lang.Object, java.lang.Object)
     */
    public Object put(Object key, Object value) {
        if (key is null)
            throw new NullPointerException();
        if (value is null)
            return remove(key);

        // handle the case where we don't have any attributes yet
        if (elements is null)
            elements = new Object[DEFAULT_SIZE];
        if (count is 0) {
            elements[0] = key;
            elements[1] = value;
            count++;
            return null;
        }

        int emptyIndex = -1;
        // replace existing value if it exists
        for (int i = 0; i < elements.length; i += 2) {
            if (elements[i] !is null) {
                if (elements[i].opEquals(key)) {
                    Object oldValue = elements[i + 1];
                    elements[i + 1] = value;
                    return oldValue;
                }
            } else if (emptyIndex is -1) {
                // keep track of the first empty index
                emptyIndex = i;
            }
        }
        // this will put the emptyIndex greater than the size but
        // that's ok because we will grow first.
        if (emptyIndex is -1)
            emptyIndex = count * 2;

        // otherwise add it to the list of elements.
        // grow if necessary
        if (elements.length <= (count * 2))
            grow();
        elements[emptyIndex] = key;
        elements[emptyIndex + 1] = value;
        count++;
        return null;
    }
    public Object put(String key, Object value) {
        return put( stringcast(key), value );
    }
    public Object put(Object key, String value) {
        return put( key, stringcast(value) );
    }
    public Object put(String key, String value) {
        return put( stringcast(key), stringcast(value) );
    }

    /**
     * @see Map#putAll(java.util.Map)
     */
    public void putAll(Map map) {
        for (Iterator i = map.keySet().iterator(); i.hasNext();) {
            Object key = i.next();
            Object value = map.get(key);
            put(key, value);
        }
    }

    /**
     * @see Map#remove(java.lang.Object)
     */
    public Object remove(Object key) {
        if (elements is null || count is 0)
            return null;
        for (int i = 0; i < elements.length; i = i + 2) {
            if (elements[i] !is null && elements[i].opEquals(key)) {
                elements[i] = null;
                Object result = elements[i + 1];
                elements[i + 1] = null;
                count--;
                return result;
            }
        }
        return null;
    }
    public Object remove(String key) {
        return remove( stringcast(key));
    }

    /* (non-Javadoc
     * Method declared on IStringPoolParticipant
     */
    public void shareStrings(StringPool set) {
        //copy elements for thread safety
        Object[] array = elements;
        if (array is null)
            return;
        for (int i = 0; i < array.length; i++) {
            Object o = array[i];
            if (cast(ArrayWrapperString)o )
                array[i] = stringcast(set.add(stringcast( o)));
        }
    }

    /**
     * @see Map#size()
     */
    public int size() {
        return count;
    }

    /**
     * Creates a new hash map with the same contents as this map.
     */
    private HashMap toHashMap() {
        HashMap result = new HashMap(size());
        for (int i = 0; i < elements.length; i = i + 2) {
            if (elements[i] !is null) {
                result.put(elements[i], elements[i + 1]);
            }
        }
        return result;
    }

    /**
     * @see Map#values()
     *
     * Note: This implementation does not conform properly to the
     * specification in the Map interface. The returned collection will not
     * be bound to this map and will not remain in sync with this map.
     */
    public Collection values() {
        Set result = new HashSet(size());
        for (int i = 1; i < elements.length; i = i + 2) {
            if (elements[i] !is null) {
                result.add(elements[i]);
            }
        }
        return result;
    }

    public int opApply (int delegate(ref Object value) dg){
        implMissing(__FILE__, __LINE__ );
        return 0;
    }
    public int opApply (int delegate(ref Object key, ref Object value) dg){
        implMissing(__FILE__, __LINE__ );
        return 0;
    }

}