1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.binding.impl;
14 import java.util.Arrays;
\r
15 import java.util.Comparator;
\r
16 import java.util.HashMap;
\r
17 import java.util.IdentityHashMap;
\r
18 import java.util.Iterator;
\r
19 import java.util.List;
\r
20 import java.util.Map;
\r
21 import java.util.Map.Entry;
\r
22 import java.util.Set;
\r
24 import org.simantics.databoard.Bindings;
\r
25 import org.simantics.databoard.adapter.AdaptException;
\r
26 import org.simantics.databoard.adapter.Adapter;
\r
27 import org.simantics.databoard.adapter.AdapterConstructionException;
\r
28 import org.simantics.databoard.binding.ArrayBinding;
\r
29 import org.simantics.databoard.binding.Binding;
\r
30 import org.simantics.databoard.binding.MapBinding;
\r
31 import org.simantics.databoard.binding.error.BindingException;
\r
32 import org.simantics.databoard.type.MapType;
\r
35 * Binds Databoard's MapType to java.util.Map and instantiates java.util.HashMap.
37 * HashMapBinding has a very poor performance. This operations cannot be performed
38 * with map operations because HashMap doesn't support exterior comparator
41 * TODO This could be optimized by inquiring whether the Key is {@link Comparable}
43 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
45 public class HashMapBinding extends MapBinding {
47 public HashMapBinding(Binding keyBinding, Binding valueBinding) {
48 super(keyBinding, valueBinding);
51 public HashMapBinding(MapType mapType, Binding keyBinding,
52 Binding valueBinding) {
53 super(mapType, keyBinding, valueBinding);
56 public void postConstruction() {}
\r
59 public Object create() {
60 return new HashMap<Object, Object>();
64 public Object create(Object[] keys, Object[] values) {
65 if (keys.length!=values.length)
66 throw new IllegalArgumentException("Equal length arrays expected");
68 int len = keys.length;
69 HashMap<Object, Object> result = new HashMap<Object, Object>(len);
71 for (int i=0; i<len; i++) {
73 key = getComparableKey(result, key);
74 Object value = values[i];
75 result.put(key, value);
82 public Object create(List<Object> keys, List<Object> values) {
83 if (keys.size()!=values.size())
84 throw new IllegalArgumentException("Equal length arrays expected");
86 int len = keys.size();
87 HashMap<Object, Object> result = new HashMap<Object, Object>(len);
89 for (int i=0; i<len; i++) {
90 Object key = keys.get(i);
91 key = getComparableKey(result, key);
92 Object value = values.get(i);
93 result.put(key, value);
100 public Object create(Map<?, ?> initialMap) throws BindingException {
101 // Replace with TreeMap. Create comparator from binding.
102 HashMap<Object, Object> result = new HashMap<Object, Object>();
103 putAll(result, initialMap);
108 public void clear(Object map) {
109 ((Map<?, ?> )map).clear();
113 public boolean containsKey(Object map, Object key) {
114 Map<?, ?> m = ((Map<?, ?> )map);
115 Binding kb = getKeyBinding();
117 for (Object v : m.keySet())
119 if (kb.equals(v, key)) return true;
125 public boolean containsValue(Object map, Object value) {
126 Map<?, ?> m = ((Map<?, ?> )map);
127 Binding vb = getValueBinding();
128 for (Object v : m.values())
130 if (vb.equals(v, value)) return true;
135 @SuppressWarnings("unchecked")
137 public Object get(Object map, Object key) {
138 Map<Object, Object> m = ((Map<Object, Object>)map);
139 Binding kb = getKeyBinding();
140 for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) m.entrySet())
142 if (kb.equals(e.getKey(), key)) return e.getValue();
148 public Object[] getKeys(Object map) {
149 Map<?, ?> m = ((Map<?, ?> )map);
150 Object[] result = m.keySet().toArray(new Object[m.size()]);
151 Arrays.sort(result, getKeyBinding());
156 public void getKeys(Object map, Set<Object> keys) throws BindingException {
157 Map<?, ?> m = ((Map<?, ?> )map);
158 keys.addAll(m.keySet());
161 @SuppressWarnings("unchecked")
\r
163 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 {
\r
164 // Assert end > from
\r
165 if (keyBinding.compare(from, end)>0) return 0;
\r
168 int dkc = dstKeyArrayBinding.size(dstKeyArray);
\r
169 int dvc = dstValueArrayBinding.size(dstValueArray);
\r
170 Adapter ka = Bindings.getTypeAdapter(keyBinding, dstKeyArrayBinding.getComponentBinding());
\r
171 Adapter va = Bindings.getTypeAdapter(valueBinding, dstValueArrayBinding.getComponentBinding());
\r
172 HashMap<Object, Object> m = ((HashMap<Object, Object>)src);
\r
174 for (Entry<Object, Object> e : m.entrySet()) {
\r
175 if (limit>=0 && i>=limit) break;
\r
176 Object k = e.getKey();
\r
177 int fk = keyBinding.compare(from, k);
\r
178 int ek = keyBinding.compare(k, end);
\r
179 boolean fromMatches = fromInclusive ? fk<=0 : fk<0;
\r
180 boolean endMatches = endInclusive ? ek<=0 : ek <0;
\r
181 if ( fromMatches && endMatches ) {
\r
182 Object dk = ka.adapt( e.getKey() );
\r
183 Object dv = va.adapt( e.getValue() );
\r
184 if (i<dkc) dstKeyArrayBinding.set(dstKeyArray, i, dk); else dstKeyArrayBinding.add(dstKeyArray, dk);
\r
185 if (i<dvc) dstValueArrayBinding.set(dstValueArray, i, dv); else dstValueArrayBinding.add(dstValueArray, dv);
\r
190 } catch (AdapterConstructionException e) {
\r
191 throw new BindingException( e );
\r
192 } catch (AdaptException e) {
\r
193 throw new BindingException( e );
\r
197 @SuppressWarnings("unchecked")
\r
199 public int count(Object src, Object from, boolean fromInclusive,
\r
200 Object end, boolean endInclusive) throws BindingException {
\r
201 // Assert end > from
\r
202 if (keyBinding.compare(from, end)>0) return 0;
\r
205 HashMap<Object, Object> m = ((HashMap<Object, Object>)src);
\r
206 for (Object k : m.keySet()) {
\r
207 int fk = keyBinding.compare(from, k);
\r
208 int ek = keyBinding.compare(k, end);
\r
209 boolean fromMatches = fromInclusive ? fk<=0 : fk<0;
\r
210 boolean endMatches = endInclusive ? ek<=0 : ek <0;
\r
211 if ( fromMatches && endMatches ) result++;
\r
217 public Object[] getValues(Object map) {
218 Map<?, ?> m = ((Map<?, ?> )map);
220 Object[] keys = getKeys(map);
221 Object[] values = new Object[len];
222 for (int i=0; i<len; i++) {
223 values[i] = m.get(keys[i]);
228 @SuppressWarnings("unchecked")
229 protected Object getComparableKey(Object map, Object key) {
230 // if (keyIsComparable) return key;
232 Map<Object, Object> m = ((Map<Object, Object>)map);
233 Binding kb = getKeyBinding();
234 for (Object k : m.keySet())
236 if (kb.equals(k, key))
242 @SuppressWarnings("unchecked")
244 public void put(Object map, Object key, Object value) {
245 Map<Object, Object> m = ((Map<Object, Object>)map);
246 Object ck = getComparableKey(m, key);
251 @SuppressWarnings("unchecked")
253 public <K, V> void putAll(Object map, Map<K, V> src) throws BindingException {
254 Map<K, V> m = ((Map<K, V> )map);
255 for (Entry<K, V> e : (Set<Entry<K, V> >) src.entrySet()) {
256 Object ck = getComparableKey(map, e.getKey());
258 m.put(e.getKey(), e.getValue());
262 @SuppressWarnings("unchecked")
\r
264 public <K, V> void getAll(Object mapFrom, Map<K, V> to) {
265 Map<K, V> m = ((Map<K, V>)mapFrom);
270 public void getAll(Object mapFrom, Object[] keys, Object[] values)
271 throws BindingException
273 Map<?, ?> m = ((Map<?, ?>)mapFrom);
276 if (len!=keys.length) throw new BindingException("Keys array is wrong size");
277 if (len!=values.length) throw new BindingException("Values array is wrong size");
279 Iterator<?> iter = m.keySet().iterator();
281 while (iter.hasNext()) {
282 keys[i++] = iter.next();
284 Arrays.sort(keys, getKeyBinding());
285 for (i=0; i<len; i++) {
286 values[i] = m.get(keys[i]);
290 @SuppressWarnings("unchecked")
292 public Object remove(Object map, Object key) {
293 Map<Object, Object> m = ((Map<Object, Object>)map);
\r
294 Binding kb = getKeyBinding();
295 for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) m.entrySet())
297 if (kb.equals(e.getKey(), key)) return m.remove(e.getKey());
303 public int size(Object map) {
304 Map<?, ?> m = ((Map<?, ?>)map);
309 public boolean isInstance(Object obj) {
310 return obj instanceof HashMap;
313 @SuppressWarnings("unchecked")
\r
315 public int deepHashValue(Object map, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
317 Map<Object, Object> m = ((Map<Object, Object>)map);
318 Set<Entry<Object, Object>> s = m.entrySet();
319 for (Entry<Object, Object> e : s) {
320 int keyHash = getKeyBinding().deepHashValue( e.getKey(), hashedObjects );
321 int valueHash = getValueBinding().deepHashValue( e.getValue(), hashedObjects );
322 result += (keyHash ^ valueHash);
327 @SuppressWarnings("unchecked")
\r
329 public Object getCeilingKey(Object map, Object key) {
330 Map<Object, Object> m = ((Map<Object, Object>)map);
331 if (m.isEmpty()) return null;
332 Comparator<Object> comparator = getKeyBinding();
334 for (Object o : m.keySet()) {
335 // We are trying to find key > o > pivot
336 int c2 = comparator.compare(key, o);
338 if (pivot==null) {pivot = o; continue;}
339 int c1 = comparator.compare(o, pivot);
345 @SuppressWarnings("unchecked")
\r
347 public Object getFirstKey(Object map) {
348 Map<Object, Object> m = (Map<Object, Object>) map;
349 if (m.isEmpty()) return null;
350 Comparator<Object> c = getKeyBinding();
351 Object result = null;
352 for (Object o : m.keySet()) {
357 if (c.compare(o, result)<0) result = o;
363 @SuppressWarnings("unchecked")
\r
365 public Object getFloorKey(Object map, Object key) {
366 Map<Object, Object> m = ((Map<Object, Object>)map);
367 if (m.isEmpty()) return null;
368 // if (m.containsKey(key)) return key;
370 Comparator<Object> comparator = getKeyBinding();
372 for (Object o : m.keySet()) {
373 // We are trying to find pivot <= o <= key
374 int c2 = comparator.compare(o, key);
377 if (pivot==null) {pivot = o; continue;}
378 int c1 = comparator.compare(pivot, o);
384 @SuppressWarnings("unchecked")
\r
386 public Object getHigherKey(Object map, Object key) {
387 Map<Object, Object> m = ((Map<Object, Object>)map);
388 if (m.isEmpty()) return null;
389 Comparator<Object> comparator = getKeyBinding();
391 for (Object o : m.keySet()) {
392 // We are trying to find key > o > pivot
393 int c2 = comparator.compare(key, o);
395 if (pivot==null) {pivot = o; continue;}
396 int c1 = comparator.compare(o, pivot);
402 @SuppressWarnings("unchecked")
\r
404 public Object getLastKey(Object map) {
405 Map<Object, Object> m = (Map<Object, Object>) map;
406 if (m.isEmpty()) return null;
407 Comparator<Object> c = getKeyBinding();
408 Object result = null;
409 for (Object o : m.keySet()) {
414 if (c.compare(o, result)>0) result = o;
420 @SuppressWarnings("unchecked")
\r
422 public Object getLowerKey(Object map, Object key) {
423 Map<Object, Object> m = ((Map<Object, Object>)map);
424 if (m.isEmpty()) return null;
425 Comparator<Object> comparator = getKeyBinding();
427 for (Object o : m.keySet()) {
428 // We are trying to find pivot < o < key
429 int c2 = comparator.compare(o, key);
431 if (pivot==null) {pivot = o; continue;}
432 int c1 = comparator.compare(pivot, o);