platform35/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerAttributeMap.java
changeset 40 eb3c938c7fef
equal deleted inserted replaced
39:2a03ec4dbf31 40:eb3c938c7fef
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2000, 2005 IBM Corporation and others.
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     IBM Corporation - initial API and implementation
       
    10  *******************************************************************************/
       
    11 package org.eclipse.core.internal.resources;
       
    12 
       
    13 import java.util.*;
       
    14 import org.eclipse.core.internal.utils.IStringPoolParticipant;
       
    15 import org.eclipse.core.internal.utils.StringPool;
       
    16 
       
    17 /**
       
    18  * A specialized map implementation that is optimized for a 
       
    19  * small set of interned strings as keys.  The provided keys
       
    20  * MUST be instances of java.lang.String.
       
    21  * 
       
    22  * Implemented as a single array that alternates keys and values.
       
    23  */
       
    24 public class MarkerAttributeMap implements Map, IStringPoolParticipant {
       
    25 	protected Object[] elements = null;
       
    26 	protected int count = 0;
       
    27 
       
    28 	// 8 attribute keys, 8 attribute values
       
    29 	protected static final int DEFAULT_SIZE = 16;
       
    30 	protected static final int GROW_SIZE = 10;
       
    31 
       
    32 	/**
       
    33 	 * Creates a new marker attribute map of default size
       
    34 	 */
       
    35 	public MarkerAttributeMap() {
       
    36 		super();
       
    37 	}
       
    38 
       
    39 	/**
       
    40 	 * Creates a new marker attribute map.
       
    41 	 * @param initialCapacity The initial number of elements that will fit in the map.
       
    42 	 */
       
    43 	public MarkerAttributeMap(int initialCapacity) {
       
    44 		elements = new Object[Math.max(initialCapacity * 2, 0)];
       
    45 	}
       
    46 
       
    47 	/**
       
    48 	 * Creates a new marker attribute map of default size
       
    49 	 * @param map The entries in the given map will be added to the new map.
       
    50 	 */
       
    51 	public MarkerAttributeMap(Map map) {
       
    52 		this(map.size());
       
    53 		putAll(map);
       
    54 	}
       
    55 
       
    56 	/* (non-Javadoc)
       
    57 	 * @see Map#clear()
       
    58 	 */
       
    59 	public void clear() {
       
    60 		elements = null;
       
    61 		count = 0;
       
    62 	}
       
    63 
       
    64 	/* (non-Javadoc)
       
    65 	 * @see Map#containsKey(java.lang.Object)
       
    66 	 */
       
    67 	public boolean containsKey(Object key) {
       
    68 		key = ((String) key).intern();
       
    69 		if (elements == null || count == 0)
       
    70 			return false;
       
    71 		for (int i = 0; i < elements.length; i = i + 2)
       
    72 			if (elements[i] == key)
       
    73 				return true;
       
    74 		return false;
       
    75 	}
       
    76 
       
    77 	/* (non-Javadoc)
       
    78 	 * @see Map#containsValue(java.lang.Object)
       
    79 	 */
       
    80 	public boolean containsValue(Object value) {
       
    81 		if (elements == null || count == 0)
       
    82 			return false;
       
    83 		for (int i = 1; i < elements.length; i = i + 2)
       
    84 			if (elements[i] != null && elements[i].equals(value))
       
    85 				return true;
       
    86 		return false;
       
    87 	}
       
    88 
       
    89 	/* (non-Javadoc)
       
    90 	 * @see Map#entrySet()
       
    91 	 * This implementation does not conform properly to the specification
       
    92 	 * in the Map interface.  The returned collection will not be bound to
       
    93 	 * this map and will not remain in sync with this map.
       
    94 	 */
       
    95 	public Set entrySet() {
       
    96 		return toHashMap().entrySet();
       
    97 	}
       
    98 
       
    99 	/* (non-Javadoc)
       
   100 	 * @see Object#equals(java.lang.Object)
       
   101 	 */
       
   102 	public boolean equals(Object o) {
       
   103 		if (!(o instanceof Map))
       
   104 			return false;
       
   105 		Map other = (Map) o;
       
   106 		//must be same size
       
   107 		if (count != other.size())
       
   108 			return false;
       
   109 
       
   110 		//keysets must be equal
       
   111 		if (!keySet().equals(other.keySet()))
       
   112 			return false;
       
   113 
       
   114 		//values for each key must be equal
       
   115 		for (int i = 0; i < elements.length; i = i + 2) {
       
   116 			if (elements[i] != null && (!elements[i + 1].equals(other.get(elements[i]))))
       
   117 				return false;
       
   118 		}
       
   119 		return true;
       
   120 	}
       
   121 
       
   122 	/* (non-Javadoc)
       
   123 	 * @see Map#get(java.lang.Object)
       
   124 	 */
       
   125 	public Object get(Object key) {
       
   126 		key = ((String) key).intern();
       
   127 		if (elements == null || count == 0)
       
   128 			return null;
       
   129 		for (int i = 0; i < elements.length; i = i + 2)
       
   130 			if (elements[i] == key)
       
   131 				return elements[i + 1];
       
   132 		return null;
       
   133 	}
       
   134 
       
   135 	/**
       
   136 	 * The capacity of the map has been exceeded, grow the array by
       
   137 	 * GROW_SIZE to accomodate more entries.
       
   138 	 */
       
   139 	protected void grow() {
       
   140 		Object[] expanded = new Object[elements.length + GROW_SIZE];
       
   141 		System.arraycopy(elements, 0, expanded, 0, elements.length);
       
   142 		elements = expanded;
       
   143 	}
       
   144 
       
   145 	/* (non-Javadoc)
       
   146 	 * @see Object#hashCode()
       
   147 	 */
       
   148 	public int hashCode() {
       
   149 		int hash = 0;
       
   150 		for (int i = 0; i < elements.length; i = i + 2) {
       
   151 			if (elements[i] != null) {
       
   152 				hash += elements[i].hashCode();
       
   153 			}
       
   154 		}
       
   155 		return hash;
       
   156 	}
       
   157 
       
   158 	/* (non-Javadoc)
       
   159 	 * @see Map#isEmpty()
       
   160 	 */
       
   161 	public boolean isEmpty() {
       
   162 		return count == 0;
       
   163 	}
       
   164 
       
   165 	/* (non-Javadoc)
       
   166 	 * @see Map#keySet()
       
   167 	 * This implementation does not conform properly to the specification
       
   168 	 * in the Map interface.  The returned collection will not be bound to
       
   169 	 * this map and will not remain in sync with this map.
       
   170 	 */
       
   171 	public Set keySet() {
       
   172 		Set result = new HashSet(size());
       
   173 		for (int i = 0; i < elements.length; i = i + 2) {
       
   174 			if (elements[i] != null) {
       
   175 				result.add(elements[i]);
       
   176 			}
       
   177 		}
       
   178 		return result;
       
   179 	}
       
   180 
       
   181 	/* (non-Javadoc)
       
   182 	 * @see Map#put(java.lang.Object, java.lang.Object)
       
   183 	 */
       
   184 	public Object put(Object key, Object value) {
       
   185 		if (key == null)
       
   186 			throw new NullPointerException();
       
   187 		if (value == null)
       
   188 			return remove(key);
       
   189 		key = ((String) key).intern();
       
   190 
       
   191 		// handle the case where we don't have any attributes yet
       
   192 		if (elements == null)
       
   193 			elements = new Object[DEFAULT_SIZE];
       
   194 		if (count == 0) {
       
   195 			elements[0] = key;
       
   196 			elements[1] = value;
       
   197 			count++;
       
   198 			return null;
       
   199 		}
       
   200 
       
   201 		// replace existing value if it exists
       
   202 		for (int i = 0; i < elements.length; i = i + 2) {
       
   203 			if (elements[i] == key) {
       
   204 				Object oldValue = elements[i + 1];
       
   205 				elements[i + 1] = value;
       
   206 				return oldValue;
       
   207 			}
       
   208 		}
       
   209 
       
   210 		// otherwise add it to the list of elements.
       
   211 		// grow if necessary
       
   212 		if (elements.length <= (count * 2))
       
   213 			grow();
       
   214 		for (int i = 0; i < elements.length; i = i + 2) {
       
   215 			if (elements[i] == null) {
       
   216 				elements[i] = key;
       
   217 				elements[i + 1] = value;
       
   218 				count++;
       
   219 				return null;
       
   220 			}
       
   221 		}
       
   222 		return null;
       
   223 	}
       
   224 
       
   225 	/* (non-Javadoc)
       
   226 	 * @see Map#putAll(java.util.Map)
       
   227 	 */
       
   228 	public void putAll(Map map) {
       
   229 		for (Iterator i = map.keySet().iterator(); i.hasNext();) {
       
   230 			Object key = i.next();
       
   231 			Object value = map.get(key);
       
   232 			put(key, value);
       
   233 		}
       
   234 	}
       
   235 
       
   236 	/* (non-Javadoc)
       
   237 	 * @see Map#remove(java.lang.Object)
       
   238 	 */
       
   239 	public Object remove(Object key) {
       
   240 		key = ((String) key).intern();
       
   241 		if (elements == null || count == 0)
       
   242 			return null;
       
   243 		for (int i = 0; i < elements.length; i = i + 2) {
       
   244 			if (elements[i] == key) {
       
   245 				elements[i] = null;
       
   246 				Object result = elements[i + 1];
       
   247 				elements[i + 1] = null;
       
   248 				count--;
       
   249 				return result;
       
   250 			}
       
   251 		}
       
   252 		return null;
       
   253 	}
       
   254 
       
   255 	/* (non-Javadoc)
       
   256 	 * @see Map#size()
       
   257 	 */
       
   258 	public int size() {
       
   259 		return count;
       
   260 	}
       
   261 
       
   262 	/* (non-Javadoc
       
   263 	 * Method declared on IStringPoolParticipant
       
   264 	 */
       
   265 	public void shareStrings(StringPool set) {
       
   266 		//copy elements for thread safety
       
   267 		Object[] array = elements;
       
   268 		if (array == null)
       
   269 			return;
       
   270 		//don't share keys because they are already interned
       
   271 		for (int i = 1; i < array.length; i = i + 2) {
       
   272 			Object o = array[i];
       
   273 			if (o instanceof String)
       
   274 				array[i] = set.add((String)o);
       
   275 			else if (o instanceof IStringPoolParticipant)
       
   276 				((IStringPoolParticipant)o).shareStrings(set);
       
   277 		}
       
   278 	}
       
   279 
       
   280 	/**
       
   281 	 * Creates a new hash map with the same contents as this map.
       
   282 	 */
       
   283 	private HashMap toHashMap() {
       
   284 		HashMap result = new HashMap(size());
       
   285 		for (int i = 0; i < elements.length; i = i + 2) {
       
   286 			if (elements[i] != null) {
       
   287 				result.put(elements[i], elements[i + 1]);
       
   288 			}
       
   289 		}
       
   290 		return result;
       
   291 	}
       
   292 
       
   293 	/* (non-Javadoc)
       
   294 	 * @see Map#values()
       
   295 	 * This implementation does not conform properly to the specification
       
   296 	 * in the Map interface.  The returned collection will not be bound to
       
   297 	 * this map and will not remain in sync with this map.
       
   298 	 */
       
   299 	public Collection values() {
       
   300 		Set result = new HashSet(size());
       
   301 		for (int i = 1; i < elements.length; i = i + 2) {
       
   302 			if (elements[i] != null) {
       
   303 				result.add(elements[i]);
       
   304 			}
       
   305 		}
       
   306 		return result;
       
   307 	}
       
   308 }