/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.binding.impl; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.adapter.Adapter; import org.simantics.databoard.adapter.AdapterConstructionException; import org.simantics.databoard.binding.ArrayBinding; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.MapBinding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.type.MapType; /** * Binds Databoard's MapType to java.util.Map and instantiates java.util.HashMap. * * HashMapBinding has a very poor performance. This operations cannot be performed * with map operations because HashMap doesn't support exterior comparator * which is required. * * TODO This could be optimized by inquiring whether the Key is {@link Comparable} * * @author Toni Kalajainen */ public class HashMapBinding extends MapBinding { public HashMapBinding(Binding keyBinding, Binding valueBinding) { super(keyBinding, valueBinding); } public HashMapBinding(MapType mapType, Binding keyBinding, Binding valueBinding) { super(mapType, keyBinding, valueBinding); } @Override public Object create() { return new HashMap(); } @Override public Object create(Object[] keys, Object[] values) { if (keys.length!=values.length) throw new IllegalArgumentException("Equal length arrays expected"); int len = keys.length; HashMap result = new HashMap(len); for (int i=0; i keys, List values) { if (keys.size()!=values.size()) throw new IllegalArgumentException("Equal length arrays expected"); int len = keys.size(); HashMap result = new HashMap(len); for (int i=0; i initialMap) throws BindingException { if (initialMap instanceof HashMap) return initialMap; // Replace with TreeMap. Create comparator from binding. HashMap result = new HashMap(); putAll(result, initialMap); return result; } @Override public void clear(Object map) { ((Map )map).clear(); } @Override public boolean containsKey(Object map, Object key) { Map m = ((Map )map); Binding kb = getKeyBinding(); for (Object v : m.keySet()) { if (kb.equals(v, key)) return true; } return false; } @Override public boolean containsValue(Object map, Object value) { Map m = ((Map )map); Binding vb = getValueBinding(); for (Object v : m.values()) { if (vb.equals(v, value)) return true; } return false; } @SuppressWarnings("unchecked") @Override public Object get(Object map, Object key) { Map m = ((Map)map); Binding kb = getKeyBinding(); for (Entry e : (Set>) m.entrySet()) { if (kb.equals(e.getKey(), key)) return e.getValue(); } return null; } @Override public Object[] getKeys(Object map) { Map m = ((Map )map); Object[] result = m.keySet().toArray(new Object[m.size()]); Arrays.sort(result, getKeyBinding()); return result; } @Override public void getKeys(Object map, Set keys) throws BindingException { Map m = ((Map )map); keys.addAll(m.keySet()); } @SuppressWarnings("unchecked") @Override public int getEntries(Object src, Object from, boolean fromInclusive, Object end, boolean endInclusive, ArrayBinding dstKeyArrayBinding, Object dstKeyArray, ArrayBinding dstValueArrayBinding, Object dstValueArray, int limit) throws BindingException { // Assert end > from if (keyBinding.compare(from, end)>0) return 0; try { int dkc = dstKeyArrayBinding.size(dstKeyArray); int dvc = dstValueArrayBinding.size(dstValueArray); Adapter ka = Bindings.getTypeAdapter(keyBinding, dstKeyArrayBinding.getComponentBinding()); Adapter va = Bindings.getTypeAdapter(valueBinding, dstValueArrayBinding.getComponentBinding()); HashMap m = ((HashMap)src); int i = 0; for (Entry e : m.entrySet()) { if (limit>=0 && i>=limit) break; Object k = e.getKey(); int fk = keyBinding.compare(from, k); int ek = keyBinding.compare(k, end); boolean fromMatches = fromInclusive ? fk<=0 : fk<0; boolean endMatches = endInclusive ? ek<=0 : ek <0; if ( fromMatches && endMatches ) { Object dk = ka.adapt( e.getKey() ); Object dv = va.adapt( e.getValue() ); if (i from if (keyBinding.compare(from, end)>0) return 0; int result = 0; HashMap m = ((HashMap)src); for (Object k : m.keySet()) { int fk = keyBinding.compare(from, k); int ek = keyBinding.compare(k, end); boolean fromMatches = fromInclusive ? fk<=0 : fk<0; boolean endMatches = endInclusive ? ek<=0 : ek <0; if ( fromMatches && endMatches ) result++; } return result; } @Override public Object[] getValues(Object map) { Map m = ((Map )map); int len = m.size(); Object[] keys = getKeys(map); Object[] values = new Object[len]; for (int i=0; i m = ((Map)map); Binding kb = getKeyBinding(); for (Object k : m.keySet()) { if (kb.equals(k, key)) return k; } return key; } @SuppressWarnings("unchecked") @Override public void put(Object map, Object key, Object value) { Map m = ((Map)map); Object ck = getComparableKey(m, key); m.remove(ck); m.put(key, value); } @SuppressWarnings("unchecked") @Override public void putAll(Object map, Map src) throws BindingException { Map m = ((Map )map); for (Entry e : (Set >) src.entrySet()) { Object ck = getComparableKey(map, e.getKey()); m.remove(ck); m.put(e.getKey(), e.getValue()); } } @SuppressWarnings("unchecked") @Override public void getAll(Object mapFrom, Map to) { Map m = ((Map)mapFrom); to.putAll(m); } @Override public void getAll(Object mapFrom, Object[] keys, Object[] values) throws BindingException { Map m = ((Map)mapFrom); int len = m.size(); if (len!=keys.length) throw new BindingException("Keys array is wrong size"); if (len!=values.length) throw new BindingException("Values array is wrong size"); Iterator iter = m.keySet().iterator(); int i=0; while (iter.hasNext()) { keys[i++] = iter.next(); } Arrays.sort(keys, getKeyBinding()); for (i=0; i m = ((Map)map); Binding kb = getKeyBinding(); for (Entry e : (Set>) m.entrySet()) { if (kb.equals(e.getKey(), key)) return m.remove(e.getKey()); } return null; } @Override public int size(Object map) { Map m = ((Map)map); return m.size(); } @Override public boolean isInstance(Object obj) { return obj instanceof HashMap; } @SuppressWarnings("unchecked") @Override public int deepHashValue(Object map, IdentityHashMap hashedObjects) throws BindingException { int result = 0; Map m = ((Map)map); Set> s = m.entrySet(); for (Entry e : s) { int keyHash = getKeyBinding().deepHashValue( e.getKey(), hashedObjects ); int valueHash = getValueBinding().deepHashValue( e.getValue(), hashedObjects ); result += (keyHash ^ valueHash); } return result; } @SuppressWarnings("unchecked") @Override public Object getCeilingKey(Object map, Object key) { Map m = ((Map)map); if (m.isEmpty()) return null; Comparator comparator = getKeyBinding(); Object pivot = null; for (Object o : m.keySet()) { // We are trying to find key > o > pivot int c2 = comparator.compare(key, o); if (c2>0) continue; if (pivot==null) {pivot = o; continue;} int c1 = comparator.compare(o, pivot); if (c1<0) pivot = o; } return pivot; } @SuppressWarnings("unchecked") @Override public Object getFirstKey(Object map) { Map m = (Map) map; if (m.isEmpty()) return null; Comparator c = getKeyBinding(); Object result = null; for (Object o : m.keySet()) { if (result==null) { result = o; continue; } if (c.compare(o, result)<0) result = o; } return result; } @SuppressWarnings("unchecked") @Override public Object getFloorKey(Object map, Object key) { Map m = ((Map)map); if (m.isEmpty()) return null; // if (m.containsKey(key)) return key; Comparator comparator = getKeyBinding(); Object pivot = null; for (Object o : m.keySet()) { // We are trying to find pivot <= o <= key int c2 = comparator.compare(o, key); if (c2==0) return o; if (c2>0) continue; if (pivot==null) {pivot = o; continue;} int c1 = comparator.compare(pivot, o); if (c1<0) pivot = o; } return pivot; } @SuppressWarnings("unchecked") @Override public Object getHigherKey(Object map, Object key) { Map m = ((Map)map); if (m.isEmpty()) return null; Comparator comparator = getKeyBinding(); Object pivot = null; for (Object o : m.keySet()) { // We are trying to find key > o > pivot int c2 = comparator.compare(key, o); if (c2>=0) continue; if (pivot==null) {pivot = o; continue;} int c1 = comparator.compare(o, pivot); if (c1<0) pivot = o; } return pivot; } @SuppressWarnings("unchecked") @Override public Object getLastKey(Object map) { Map m = (Map) map; if (m.isEmpty()) return null; Comparator c = getKeyBinding(); Object result = null; for (Object o : m.keySet()) { if (result==null) { result = o; continue; } if (c.compare(o, result)>0) result = o; } return result; } @SuppressWarnings("unchecked") @Override public Object getLowerKey(Object map, Object key) { Map m = ((Map)map); if (m.isEmpty()) return null; Comparator comparator = getKeyBinding(); Object pivot = null; for (Object o : m.keySet()) { // We are trying to find pivot < o < key int c2 = comparator.compare(o, key); if (c2>=0) continue; if (pivot==null) {pivot = o; continue;} int c1 = comparator.compare(pivot, o); if (c1<0) pivot = o; } return pivot; } }