Copyright (c) 2000, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation James Blackburn (Broadcom Corp.) - ongoing development Lars Vogel - Bug 473427
/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * James Blackburn (Broadcom Corp.) - ongoing development * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 *******************************************************************************/
package org.eclipse.core.internal.resources; import java.util.*; import org.eclipse.core.internal.utils.IStringPoolParticipant; import org.eclipse.core.internal.utils.StringPool;
A specialized map implementation that is optimized for a small set of interned strings as keys. The provided keys MUST be instances of java.lang.String. Implemented as a single array that alternates keys and values.
/** * A specialized map implementation that is optimized for a * small set of interned strings as keys. The provided keys * MUST be instances of java.lang.String. * * Implemented as a single array that alternates keys and values. */
@SuppressWarnings("unchecked") public class MarkerAttributeMap<V> implements Map<String, V>, IStringPoolParticipant { protected Object[] elements = null; protected int count = 0; // 8 attribute keys, 8 attribute values protected static final int DEFAULT_SIZE = 16; protected static final int GROW_SIZE = 10; private static final Object[] EMPTY = new Object[0];
Creates a new marker attribute map of default size
/** * Creates a new marker attribute map of default size */
public MarkerAttributeMap() { this(DEFAULT_SIZE); }
Creates a new marker attribute map.
Params:
  • initialCapacity – The initial number of elements that will fit in the map.
/** * Creates a new marker attribute map. * @param initialCapacity The initial number of elements that will fit in the map. */
public MarkerAttributeMap(int initialCapacity) { elements = initialCapacity > 0 ? new Object[initialCapacity * 2] : EMPTY; }
Creates a new marker attribute map of default size
Params:
  • map – The entries in the given map will be added to the new map.
/** * Creates a new marker attribute map of default size * @param map The entries in the given map will be added to the new map. */
public MarkerAttributeMap(Map<String, ? extends V> map) { this(map.size()); putAll(map); } @Override public void clear() { count = 0; elements = EMPTY; } @Override public boolean containsKey(Object key) { if (count == 0) return false; key = ((String) key).intern(); for (int i = 0; i < elements.length; i = i + 2) if (elements[i] == key) return true; return false; } @Override public boolean containsValue(Object value) { if (count == 0) return false; for (int i = 1; i < elements.length; i = i + 2) if (elements[i] != null && elements[i].equals(value)) return true; return false; }
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.
/** * 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. */
@Override public Set<Entry<String, V>> entrySet() { return toHashMap().entrySet(); } @Override public boolean equals(Object o) { if (!(o instanceof Map)) return false; Map<String, V> other = (Map<String, V>) o; //must be same size if (count != other.size()) return false; if (count == 0) return true; //keysets must be equal if (!keySet().equals(other.keySet())) return false; //values for each key must be equal for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] != null && (!elements[i + 1].equals(other.get(elements[i])))) return false; } return true; } @Override public V get(Object key) { if (count == 0) return null; key = ((String) key).intern(); for (int i = 0; i < elements.length; i = i + 2) if (elements[i] == key) return (V) elements[i + 1]; return null; }
The capacity of the map has been exceeded, grow the array by GROW_SIZE to accomodate more entries.
/** * 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; } @Override public int hashCode() { int hash = 0; if (count == 0) return hash; for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] != null) { hash += elements[i].hashCode(); } } return hash; } @Override public boolean isEmpty() { return count == 0; }
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.
/** * 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. */
@Override public Set<String> keySet() { Set<String> result = new HashSet<>(size()); if (count == 0) return result; for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] != null) { result.add((String) elements[i]); } } return result; } @Override public V put(String k, V value) { if (k == null) throw new NullPointerException(); if (value == null) return remove(k); String key = k.intern(); if (elements.length <= (count * 2)) grow(); // handle the case where we don't have any attributes yet if (count == 0) { elements[0] = key; elements[1] = value; count++; return null; } // replace existing value if it exists for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] == key) { Object oldValue = elements[i + 1]; elements[i + 1] = value; return (V) oldValue; } } // otherwise add it to the list of elements. for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] == null) { elements[i] = key; elements[i + 1] = value; count++; return null; } } return null; } @Override public void putAll(Map<? extends String, ? extends V> map) { for (Map.Entry<? extends String, ? extends V> e : map.entrySet()) put(e.getKey(), e.getValue()); } @Override public V remove(Object key) { if (count == 0) return null; key = ((String) key).intern(); for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] == key) { elements[i] = null; Object result = elements[i + 1]; elements[i + 1] = null; count--; return (V) result; } } return null; } @Override public int size() { return count; } @Override public void shareStrings(StringPool set) { //copy elements for thread safety Object[] array = elements; if (array == null) return; //don't share keys because they are already interned for (int i = 1; i < array.length; i = i + 2) { Object o = array[i]; if (o instanceof String) array[i] = set.add((String) o); else if (o instanceof IStringPoolParticipant) ((IStringPoolParticipant) o).shareStrings(set); } }
Creates a new hash map with the same contents as this map.
/** * Creates a new hash map with the same contents as this map. */
private HashMap<String, V> toHashMap() { HashMap<String, V> result = new HashMap<>(size()); if (count == 0) return result; for (int i = 0; i < elements.length; i = i + 2) { if (elements[i] != null) { result.put((String) elements[i], (V) elements[i + 1]); } } return result; }
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.
/** * 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. */
@Override public Collection<V> values() { Set<V> result = new HashSet<>(size()); if (count == 0) return result; for (int i = 1; i < elements.length; i = i + 2) { if (elements[i] != null) { result.add((V) elements[i]); } } return result; } }