Selaa lähdekoodia

fix: RandomAccessMap # putAll
fix: RandomAccessMap # toString
fix: RandomAccessMap.ValueListAdapter # contains
fix: RandomAccessMap.EntryListAdapter # contains
fix: RandomAccessMap.EntryListAdapter # set
fix: RandomAccessMap.KeyListAdapter # set
fix: RandomAccessMap.EntryAdapter # equals

Ranides Atterwim 11 vuotta sitten
vanhempi
commit
119288c690

+ 60 - 22
src/main/java/net/ranides/assira/collection/map/RandomAccessMap.java

@@ -17,6 +17,7 @@ import java.util.Map;
 import java.util.RandomAccess;
 import java.util.Set;
 import net.ranides.assira.generic.ValueUtils;
+import net.ranides.assira.text.StrBuilder;
 
 /**
  * Usuwanie jest realizowane w czasie O(N), reszta idzie bardzo ładnie.
@@ -109,8 +110,8 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
     }
 
     @Override
-    public void putAll(Map<? extends K, ? extends V> m) {
-        for(Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+    public void putAll(Map<? extends K, ? extends V> values) {
+        for(Map.Entry<? extends K, ? extends V> entry : values.entrySet()) {
             put(entry.getKey(), entry.getValue());
         }
     }
@@ -140,6 +141,18 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
     public Iterator<V> iterator() {
         return asListAdapter().iterator();
     }
+	
+	@Override
+	public String toString() {
+		StrBuilder sb = new StrBuilder();
+		sb.append('{');
+		sb.list(", ");
+		for(K key : keys) {
+			sb.item().append(key).append('=').append(map.get(key));
+		}
+		sb.append('}');
+		return sb.toString();
+	}
     
     private class ValueListAdapter extends AbstractList<V> implements RandomAccess {
 
@@ -172,7 +185,7 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
         @Override
         @SuppressWarnings("element-type-mismatch")
         public boolean contains(Object value) {
-            return map.containsKey(value);
+            return map.containsValue(value);
         }
         
     }
@@ -213,9 +226,10 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
             if( map.containsKey(element) ) {
                 throw new IllegalArgumentException("key conflict. Key already exists");
             }
-            map.put(element, map.remove(keys.get(index)));
+			K prev = keys.get(index);
+            map.put(element, map.remove(prev));
             keys.set(index, element);
-            return null;
+            return prev;
         }
 
     }
@@ -233,12 +247,14 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
                 return false;
             }
             Entry<?,?> element = (Entry<?,?>)o;
-            for(Entry<K,V> entry : map.entrySet()) {
-                if( element.equals(entry) ) {
-                    return true;
-                }
-            }
-            return false;
+			Object k = element.getKey();
+			Object v = element.getValue();
+			V found = map.get(k);
+			if(null == found) {
+				return (null == v) && map.containsKey(k);
+			} else {
+				return found.equals(v);
+			}
         }
 
         @Override
@@ -281,18 +297,20 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
 
         @Override
         public Entry<K, V> get(int index) {
-            return new EntryAdapter(index);
+            return new EntryAdapter(RandomAccessMap.this, index);
         }
 
         @Override
         public Entry<K, V> set(int index, Entry<K, V> element) {
-            if( map.containsKey(element.getKey()) ) {
-                throw new IllegalArgumentException("key conflict. Key already exists");
-            }
             K pkey = keys.get(index);
             V pval = map.get(pkey);
+			
+			if( !pkey.equals(element.getKey()) && map.containsKey(element.getKey()) ) {
+                throw new IllegalArgumentException("key conflict. Key already exists");
+            }
             
-            map.put(element.getKey(), map.remove(keys.get(index)));
+			map.remove(keys.get(index));
+            map.put(element.getKey(), element.getValue());
             keys.set(index, element.getKey());
             
             return new AbstractMap.SimpleImmutableEntry(pkey, pval);
@@ -300,28 +318,48 @@ public class RandomAccessMap<K,V> implements ListableMap<K, V> {
 
     }
     
-    private class EntryAdapter implements Entry<K,V> {
+    private static class EntryAdapter<K,V> implements Entry<K,V> {
         
+        private final RandomAccessMap<K,V> parent;
         private final int index;
 
-        public EntryAdapter(int index) {
+        public EntryAdapter(RandomAccessMap<K,V> parent, int index) {
+			this.parent = parent;
             this.index = index;
         }
 
         @Override
         public K getKey() {
-            return keys.get(index);
+            return parent.keys.get(index);
         }
 
         @Override
         public V getValue() {
-            return map.get(keys.get(index));
+            return parent.map.get(parent.keys.get(index));
         }
 
         @Override
         public V setValue(V value) {
-            return map.put(keys.get(index), value);
+            return parent.map.put(parent.keys.get(index), value);
         }
-        
+
+		@Override
+		public int hashCode() {
+			return this.index;
+		}
+
+		@Override
+		public boolean equals(Object object) {
+			if(object instanceof EntryAdapter<?,?>) {
+				EntryAdapter<?,?> entry = (EntryAdapter<?,?>)object;
+				return entry.parent==parent && entry.index == index;
+			}
+			if(object instanceof Entry) {
+				final Entry<?,?> entry = (Entry<?,?>)object;
+				return ValueUtils.equals(entry.getKey(), getKey()) && ValueUtils.equals(entry.getValue(), getValue());
+			}
+			return false;
+		}
+		
     }
 }

+ 201 - 0
src/test/java/net/ranides/assira/collection/map/RandomAccessMapTest.java

@@ -0,0 +1,201 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.map;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import net.ranides.assira.collection.SetUtils;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author msieron
+ */
+
+
+public class RandomAccessMapTest {
+	
+	private RandomAccessMap<String, Integer> make() {
+		RandomAccessMap<String, Integer> map = new RandomAccessMap<>();
+		map.put("a", 10);
+		map.put("q", 20);
+		map.put("s", 15);
+		map.put("d", 12);
+		map.put("x-end", 1);
+		return map;
+	}
+	
+	@Test
+	public void testBasic() {
+		RandomAccessMap<String, Integer> map = make();
+		TreeMap<String, Integer> imap = new TreeMap<>();
+		imap.put("u-a", 101);
+		imap.put("u-b", 102);
+		imap.put("u-c", 103);
+		map.putAll(imap);
+		
+		assertEquals("{a=10, q=20, s=15, d=12, x-end=1, u-a=101, u-b=102, u-c=103}", map.toString());
+		assertEquals(8, map.size());
+		assertFalse( map.isEmpty());
+		
+		assertEquals(Arrays.asList("a","q", "s", "d", "x-end", "u-a", "u-b", "u-c"), map.keysList() );
+		assertEquals(SetUtils.asHashSet("a","q", "s", "d", "x-end", "u-a", "u-b", "u-c"), map.keySet());
+		
+		assertEquals(10, map.remove("a").intValue());
+		assertEquals(15, map.remove("s").intValue());
+		assertNull( map.remove("?"));
+		
+		assertEquals("{q=20, d=12, x-end=1, u-a=101, u-b=102, u-c=103}", map.toString());
+		
+		assertEquals(12, map.put("d", 10).intValue());
+		
+		assertEquals("{q=20, d=10, x-end=1, u-a=101, u-b=102, u-c=103}", map.toString());
+		
+		assertTrue( map.containsValue(1));
+		assertTrue( map.containsValue(103));
+		assertTrue( map.containsValue(20));
+		assertFalse( map.containsValue(99));
+		
+		map.clear();
+		assertEquals(0, map.size());
+		assertTrue( map.isEmpty());
+	}
+	
+	@Test
+	public void testListAdapter() {
+		RandomAccessMap<String, Integer> map = make();
+		List<Integer> adapter = map.asListAdapter();
+		Collection<Integer> values = map.values();
+		
+		assertEquals(adapter, values);
+		assertEquals( adapter.getClass(), values.getClass()); // that's implementation detail but...
+		assertEquals( adapter.iterator().getClass(), map.iterator().getClass()); // that's implementation detail but...
+		
+		
+		assertEquals(Arrays.asList(10, 20, 15, 12, 1), adapter);
+		
+		
+		assertTrue(adapter.contains(10));
+		assertTrue(adapter.contains(20));
+		assertFalse(adapter.contains(80));
+		
+		assertFalse(adapter.remove((Integer)80));
+		assertTrue(adapter.remove((Integer)15));
+		assertFalse(map.containsKey("s"));
+		
+		assertEquals(10, adapter.remove(0).intValue());
+		assertFalse(map.containsKey("a"));
+		
+		assertEquals(12, adapter.set(1, 99).intValue());
+		assertEquals(99, map.get("d").intValue());
+	}
+	
+	@Test
+	public void testEntryAdapter() {
+		RandomAccessMap<String, Integer> map = make();
+		List<Entry<String,Integer>> adapter = map.entryList();
+		Set<Entry<String,Integer>> set = map.entrySet();
+		
+		assertEquals(set, adapter);
+		assertEquals(set.getClass(), adapter.getClass()); // that's implementation detail but...
+				
+		List<String> entries = new ArrayList<>();
+		List<String> expected = Arrays.asList("a=10","q=20","s=15","d=12","x-end=1");
+		
+		for(Entry<String,Integer> entry : adapter) {
+			entries.add(entry.getKey()+"="+entry.getValue());
+		}
+		assertEquals(expected, entries);
+		
+		assertTrue( adapter.add(new AbstractMap.SimpleEntry<>("H",5)) );
+		assertTrue( adapter.add(new AbstractMap.SimpleEntry<>("null",(Integer)null)) );
+		assertEquals(5, map.get("H").intValue() );
+		
+		assertTrue(adapter.contains(new AbstractMap.SimpleEntry<>("q",20)));
+		assertFalse(adapter.contains(new AbstractMap.SimpleEntry<>("?",20)));
+		assertFalse(adapter.contains(new AbstractMap.SimpleEntry<>("q",17)));
+		assertFalse(adapter.contains(new AbstractMap.SimpleEntry<>("q",null)));
+		assertFalse(adapter.contains(new AbstractMap.SimpleEntry<>("?",null)));
+		assertTrue(adapter.contains(new AbstractMap.SimpleEntry<>("null",null)));
+		
+		assertFalse( adapter.remove(new AbstractMap.SimpleEntry<>("q",2)) );
+		assertTrue( map.containsKey("q"));
+		
+		assertTrue( adapter.remove(new AbstractMap.SimpleEntry<>("q",20)) );
+		assertFalse( map.containsKey("q"));
+		
+		assertEquals("d", adapter.remove(2).getKey());
+		assertFalse( map.containsKey("d"));
+		
+		// {a=10, s=15, x-end=1, H=5, null=}
+		
+		adapter.set(1, new AbstractMap.SimpleEntry<>("S",7));
+		assertEquals(7, map.get("S").intValue());
+		assertNull( map.get("s"));
+		
+		adapter.set(1, new AbstractMap.SimpleEntry<>("S",9));
+		assertEquals(9, map.get("S").intValue());
+		
+		try {
+			adapter.set(2, new AbstractMap.SimpleEntry<>("S",9));
+			fail("IllegalArgumentException expected");
+		} catch(IllegalArgumentException ex) {
+			assertTrue(true);
+		}
+		
+		assertEquals("{a=10, S=9, x-end=1, H=5, null=}", map.toString());
+		adapter.get(2).setValue(111);
+		assertEquals("{a=10, S=9, x-end=111, H=5, null=}", map.toString());
+		
+		assertTrue(adapter.get(1).equals(new AbstractMap.SimpleEntry<>("S",9)));
+		assertFalse(adapter.get(1).equals(new AbstractMap.SimpleEntry<>("S",19)));
+		assertFalse(adapter.get(1).equals(new Object()));
+		
+	}
+	
+	@Test
+	public void testKeysAdapter() {
+		RandomAccessMap<String, Integer> map = make();
+		List<String> adapter = map.keysList();
+		Set<String> set = map.keySet();
+		
+		assertEquals(set, adapter);
+		assertEquals(set.getClass(), adapter.getClass()); // that's implementation detail but...
+		
+		assertEquals("{a=10, q=20, s=15, d=12, x-end=1}", map.toString() );
+		
+		assertEquals("s", adapter.remove(2));
+		assertEquals("{a=10, q=20, d=12, x-end=1}", map.toString() );
+		
+		assertTrue( adapter.remove("d"));
+		assertFalse( adapter.remove("?"));
+		
+		assertEquals("{a=10, q=20, x-end=1}", map.toString() );
+		assertEquals(3, adapter.size());
+		
+		try {
+			adapter.set(2, "a");
+			fail("IllegalArgumentException expected");
+		} catch(IllegalArgumentException ex) {
+			assertTrue(true);
+		}
+		
+		assertEquals("q", adapter.set(1, "Q"));
+		assertEquals("{a=10, Q=20, x-end=1}", map.toString() );
+		
+		adapter.clear();
+		assertTrue( map.isEmpty() );
+	}
+	
+}