/** * <copyright> * * Copyright (c) 2013-2016 Thales Global Services S.A.S. * 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: * Thales Global Services S.A.S. - initial API and implementation * * </copyright> */ package org.eclipse.emf.diffmerge.util.structures.comparable; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.diffmerge.util.structures.StructuresUtil; import org.eclipse.emf.diffmerge.util.structures.comparable.IComparableStructure.IComparableMapEntry; /** * A BasicEMap of Comparable elements which is itself Comparable. * Null keys and values are accepted by default. * The natural order of maps is derived from the natural order of their entries, * at the cost of ordering the entries (n*log(n) performance). * @param <K> the type of the keys * @param <V> the type of the values * @author Olivier Constant */ public class ComparableHashMap<K extends Comparable<?>, V extends Comparable<?>> extends BasicEMap<K, V> implements IComparableStructure<IComparableMapEntry<K, V>> { /** The serial version ID */ private static final long serialVersionUID = 1L; /** Whether equals rather than == must be used to compare keys */ private final boolean _useEqualsForKeys; /** Whether equals rather than == must be used to compare values */ private final boolean _useEqualsForValues; /** * Constructor for empty map and usage of == instead of equals for keys and values */ public ComparableHashMap() { this(true, true); } /** * Constructor for empty map * @param useEqualsForKeys_p whether equals rather than == must be used to compare keys * @param useEqualsForValues_p whether equals rather than == must be used to compare values */ public ComparableHashMap(boolean useEqualsForKeys_p, boolean useEqualsForValues_p) { super(); _useEqualsForKeys = useEqualsForKeys_p; _useEqualsForValues = useEqualsForValues_p; } /** * Constructor for empty map with the given initial capacity * @param initialCapacity_p a positive int * @param useEqualsForKeys_p whether equals rather than == must be used to compare keys * @param useEqualsForValues_p whether equals rather than == must be used to compare values */ public ComparableHashMap(int initialCapacity_p, boolean useEqualsForKeys_p, boolean useEqualsForValues_p) { super(initialCapacity_p); _useEqualsForKeys = useEqualsForKeys_p; _useEqualsForValues = useEqualsForValues_p; } /** * Constructor for a map filled with the content of the given map * @param map_p a non-null, potentially empty map * @param useEqualsForKeys_p whether equals rather than == must be used to compare keys * @param useEqualsForValues_p whether equals rather than == must be used to compare values */ public ComparableHashMap(Map<? extends K, ? extends V> map_p, boolean useEqualsForKeys_p, boolean useEqualsForValues_p) { super(map_p); _useEqualsForKeys = useEqualsForKeys_p; _useEqualsForValues = useEqualsForValues_p; } /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(IComparableStructure<?> o_p) { return STRUCTURE_COMPARATOR.compare(this, o_p); } /** * @see org.eclipse.emf.diffmerge.util.structures.comparable.IComparableStructure#getCompareIterator() */ @SuppressWarnings({ "unchecked", "rawtypes" }) public Iterator<IComparableMapEntry<K, V>> getCompareIterator() { // Entries are sorted by natural order Object[] contents = toArray(); Arrays.sort(contents); return (Iterator)Arrays.asList(contents).iterator(); } /** * @see org.eclipse.emf.common.util.BasicEMap#newEntry(int, java.lang.Object, java.lang.Object) */ @Override protected BasicEMap.Entry<K, V> newEntry(int hash, K key, V value) { validateKey(key); validateValue(value); return new ComparableEntryImpl(hash, key, value); } /** * @see org.eclipse.emf.common.util.BasicEMap#newList() */ @Override protected BasicEList<BasicEMap.Entry<K, V>> newList() { return new BasicEList<BasicEMap.Entry<K, V>>() { private static final long serialVersionUID = 1L; @Override public Object [] newData(int listCapacity) { return new ComparableHashMap.ComparableEntryImpl[listCapacity]; } }; } /** * @see org.eclipse.emf.common.util.AbstractEList#toString() */ @Override public String toString() { return StructuresUtil.toCollectionString(this); } /** * @see org.eclipse.emf.common.util.BasicEMap#useEqualsForKey() */ @Override protected boolean useEqualsForKey() { return _useEqualsForKeys; } /** * @see org.eclipse.emf.common.util.BasicEMap#useEqualsForValue() */ @Override protected boolean useEqualsForValue() { return _useEqualsForValues; } /** * An extension of BasicEMap.EntryImpl which is Comparable. */ protected class ComparableEntryImpl extends EntryImpl implements IComparableMapEntry<K, V> { /** * Constructor * @param hash_p the hash code of the key * @param key_p the key * @param value_p the value */ public ComparableEntryImpl(int hash_p, K key_p, V value_p) { super(hash_p, key_p, value_p); } /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(IComparableStructure<?> o_p) { return STRUCTURE_COMPARATOR.compare(this, o_p); } /** * @see org.eclipse.emf.diffmerge.util.structures.comparable.IComparableStructure#getCompareIterator() */ public Iterator<Comparable<?>> getCompareIterator() { return Arrays.asList(getKey(), getValue()).iterator(); } /** * @see org.eclipse.emf.common.util.BasicEMap.EntryImpl#toString() */ @Override public String toString() { return StructuresUtil.toMapEntryString(this); } } }