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);
57 public Object create() {
\r
58 return new HashMap<Object, Object>();
\r
62 public Object create(Object[] keys, Object[] values) {
63 if (keys.length!=values.length)
64 throw new IllegalArgumentException("Equal length arrays expected");
66 int len = keys.length;
67 HashMap<Object, Object> result = new HashMap<Object, Object>(len);
69 for (int i=0; i<len; i++) {
71 key = getComparableKey(result, key);
72 Object value = values[i];
73 result.put(key, value);
80 public Object create(List<Object> keys, List<Object> values) {
81 if (keys.size()!=values.size())
82 throw new IllegalArgumentException("Equal length arrays expected");
84 int len = keys.size();
85 HashMap<Object, Object> result = new HashMap<Object, Object>(len);
87 for (int i=0; i<len; i++) {
88 Object key = keys.get(i);
89 key = getComparableKey(result, key);
90 Object value = values.get(i);
91 result.put(key, value);
98 public Object create(Map<?, ?> initialMap) throws BindingException {
\r
99 if (initialMap instanceof HashMap)
\r
102 // Replace with TreeMap. Create comparator from binding.
103 HashMap<Object, Object> result = new HashMap<Object, Object>();
104 putAll(result, initialMap);
109 public void clear(Object map) {
110 ((Map<?, ?> )map).clear();
114 public boolean containsKey(Object map, Object key) {
115 Map<?, ?> m = ((Map<?, ?> )map);
116 Binding kb = getKeyBinding();
118 for (Object v : m.keySet())
120 if (kb.equals(v, key)) return true;
126 public boolean containsValue(Object map, Object value) {
127 Map<?, ?> m = ((Map<?, ?> )map);
128 Binding vb = getValueBinding();
129 for (Object v : m.values())
131 if (vb.equals(v, value)) return true;
136 @SuppressWarnings("unchecked")
138 public Object get(Object map, Object key) {
139 Map<Object, Object> m = ((Map<Object, Object>)map);
140 Binding kb = getKeyBinding();
141 for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) m.entrySet())
143 if (kb.equals(e.getKey(), key)) return e.getValue();
149 public Object[] getKeys(Object map) {
150 Map<?, ?> m = ((Map<?, ?> )map);
151 Object[] result = m.keySet().toArray(new Object[m.size()]);
152 Arrays.sort(result, getKeyBinding());
157 public void getKeys(Object map, Set<Object> keys) throws BindingException {
158 Map<?, ?> m = ((Map<?, ?> )map);
159 keys.addAll(m.keySet());
162 @SuppressWarnings("unchecked")
\r
164 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
165 // Assert end > from
\r
166 if (keyBinding.compare(from, end)>0) return 0;
\r
169 int dkc = dstKeyArrayBinding.size(dstKeyArray);
\r
170 int dvc = dstValueArrayBinding.size(dstValueArray);
\r
171 Adapter ka = Bindings.getTypeAdapter(keyBinding, dstKeyArrayBinding.getComponentBinding());
\r
172 Adapter va = Bindings.getTypeAdapter(valueBinding, dstValueArrayBinding.getComponentBinding());
\r
173 HashMap<Object, Object> m = ((HashMap<Object, Object>)src);
\r
175 for (Entry<Object, Object> e : m.entrySet()) {
\r
176 if (limit>=0 && i>=limit) break;
\r
177 Object k = e.getKey();
\r
178 int fk = keyBinding.compare(from, k);
\r
179 int ek = keyBinding.compare(k, end);
\r
180 boolean fromMatches = fromInclusive ? fk<=0 : fk<0;
\r
181 boolean endMatches = endInclusive ? ek<=0 : ek <0;
\r
182 if ( fromMatches && endMatches ) {
\r
183 Object dk = ka.adapt( e.getKey() );
\r
184 Object dv = va.adapt( e.getValue() );
\r
185 if (i<dkc) dstKeyArrayBinding.set(dstKeyArray, i, dk); else dstKeyArrayBinding.add(dstKeyArray, dk);
\r
186 if (i<dvc) dstValueArrayBinding.set(dstValueArray, i, dv); else dstValueArrayBinding.add(dstValueArray, dv);
\r
191 } catch (AdapterConstructionException e) {
\r
192 throw new BindingException( e );
\r
193 } catch (AdaptException e) {
\r
194 throw new BindingException( e );
\r
198 @SuppressWarnings("unchecked")
\r
200 public int count(Object src, Object from, boolean fromInclusive,
\r
201 Object end, boolean endInclusive) throws BindingException {
\r
202 // Assert end > from
\r
203 if (keyBinding.compare(from, end)>0) return 0;
\r
206 HashMap<Object, Object> m = ((HashMap<Object, Object>)src);
\r
207 for (Object k : m.keySet()) {
\r
208 int fk = keyBinding.compare(from, k);
\r
209 int ek = keyBinding.compare(k, end);
\r
210 boolean fromMatches = fromInclusive ? fk<=0 : fk<0;
\r
211 boolean endMatches = endInclusive ? ek<=0 : ek <0;
\r
212 if ( fromMatches && endMatches ) result++;
\r
218 public Object[] getValues(Object map) {
219 Map<?, ?> m = ((Map<?, ?> )map);
221 Object[] keys = getKeys(map);
222 Object[] values = new Object[len];
223 for (int i=0; i<len; i++) {
224 values[i] = m.get(keys[i]);
229 @SuppressWarnings("unchecked")
230 protected Object getComparableKey(Object map, Object key) {
231 // if (keyIsComparable) return key;
233 Map<Object, Object> m = ((Map<Object, Object>)map);
234 Binding kb = getKeyBinding();
235 for (Object k : m.keySet())
237 if (kb.equals(k, key))
243 @SuppressWarnings("unchecked")
245 public void put(Object map, Object key, Object value) {
246 Map<Object, Object> m = ((Map<Object, Object>)map);
247 Object ck = getComparableKey(m, key);
252 @SuppressWarnings("unchecked")
254 public <K, V> void putAll(Object map, Map<K, V> src) throws BindingException {
255 Map<K, V> m = ((Map<K, V> )map);
256 for (Entry<K, V> e : (Set<Entry<K, V> >) src.entrySet()) {
257 Object ck = getComparableKey(map, e.getKey());
259 m.put(e.getKey(), e.getValue());
263 @SuppressWarnings("unchecked")
\r
265 public <K, V> void getAll(Object mapFrom, Map<K, V> to) {
266 Map<K, V> m = ((Map<K, V>)mapFrom);
271 public void getAll(Object mapFrom, Object[] keys, Object[] values)
272 throws BindingException
274 Map<?, ?> m = ((Map<?, ?>)mapFrom);
277 if (len!=keys.length) throw new BindingException("Keys array is wrong size");
278 if (len!=values.length) throw new BindingException("Values array is wrong size");
280 Iterator<?> iter = m.keySet().iterator();
282 while (iter.hasNext()) {
283 keys[i++] = iter.next();
285 Arrays.sort(keys, getKeyBinding());
286 for (i=0; i<len; i++) {
287 values[i] = m.get(keys[i]);
291 @SuppressWarnings("unchecked")
293 public Object remove(Object map, Object key) {
294 Map<Object, Object> m = ((Map<Object, Object>)map);
\r
295 Binding kb = getKeyBinding();
296 for (Entry<Object, Object> e : (Set<Entry<Object, Object>>) m.entrySet())
298 if (kb.equals(e.getKey(), key)) return m.remove(e.getKey());
304 public int size(Object map) {
305 Map<?, ?> m = ((Map<?, ?>)map);
310 public boolean isInstance(Object obj) {
311 return obj instanceof HashMap;
314 @SuppressWarnings("unchecked")
\r
316 public int deepHashValue(Object map, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
318 Map<Object, Object> m = ((Map<Object, Object>)map);
319 Set<Entry<Object, Object>> s = m.entrySet();
320 for (Entry<Object, Object> e : s) {
321 int keyHash = getKeyBinding().deepHashValue( e.getKey(), hashedObjects );
322 int valueHash = getValueBinding().deepHashValue( e.getValue(), hashedObjects );
323 result += (keyHash ^ valueHash);
328 @SuppressWarnings("unchecked")
\r
330 public Object getCeilingKey(Object map, Object key) {
331 Map<Object, Object> m = ((Map<Object, Object>)map);
332 if (m.isEmpty()) return null;
333 Comparator<Object> comparator = getKeyBinding();
335 for (Object o : m.keySet()) {
336 // We are trying to find key > o > pivot
337 int c2 = comparator.compare(key, o);
339 if (pivot==null) {pivot = o; continue;}
340 int c1 = comparator.compare(o, pivot);
346 @SuppressWarnings("unchecked")
\r
348 public Object getFirstKey(Object map) {
349 Map<Object, Object> m = (Map<Object, Object>) map;
350 if (m.isEmpty()) return null;
351 Comparator<Object> c = getKeyBinding();
352 Object result = null;
353 for (Object o : m.keySet()) {
358 if (c.compare(o, result)<0) result = o;
364 @SuppressWarnings("unchecked")
\r
366 public Object getFloorKey(Object map, Object key) {
367 Map<Object, Object> m = ((Map<Object, Object>)map);
368 if (m.isEmpty()) return null;
369 // if (m.containsKey(key)) return key;
371 Comparator<Object> comparator = getKeyBinding();
373 for (Object o : m.keySet()) {
374 // We are trying to find pivot <= o <= key
375 int c2 = comparator.compare(o, key);
378 if (pivot==null) {pivot = o; continue;}
379 int c1 = comparator.compare(pivot, o);
385 @SuppressWarnings("unchecked")
\r
387 public Object getHigherKey(Object map, Object key) {
388 Map<Object, Object> m = ((Map<Object, Object>)map);
389 if (m.isEmpty()) return null;
390 Comparator<Object> comparator = getKeyBinding();
392 for (Object o : m.keySet()) {
393 // We are trying to find key > o > pivot
394 int c2 = comparator.compare(key, o);
396 if (pivot==null) {pivot = o; continue;}
397 int c1 = comparator.compare(o, pivot);
403 @SuppressWarnings("unchecked")
\r
405 public Object getLastKey(Object map) {
406 Map<Object, Object> m = (Map<Object, Object>) map;
407 if (m.isEmpty()) return null;
408 Comparator<Object> c = getKeyBinding();
409 Object result = null;
410 for (Object o : m.keySet()) {
415 if (c.compare(o, result)>0) result = o;
421 @SuppressWarnings("unchecked")
\r
423 public Object getLowerKey(Object map, Object key) {
424 Map<Object, Object> m = ((Map<Object, Object>)map);
425 if (m.isEmpty()) return null;
426 Comparator<Object> comparator = getKeyBinding();
428 for (Object o : m.keySet()) {
429 // We are trying to find pivot < o < key
430 int c2 = comparator.compare(o, key);
432 if (pivot==null) {pivot = o; continue;}
433 int c1 = comparator.compare(pivot, o);