From 7aac418f1ef70d8e99e06cf857d4610c97c6a4e4 Mon Sep 17 00:00:00 2001 From: johnmcclean Date: Fri, 7 Dec 2018 16:43:24 +0000 Subject: [PATCH 1/4] More unit tests for Maps --- .../src/main/java/cyclops/data/HashMap.java | 8 +- .../src/main/java/cyclops/data/base/HAMT.java | 11 +- .../test/java/cyclops/data/HashMapTest.java | 50 +++++- .../cyclops/data/ImmutableHashMapTest.java | 2 +- .../test/java/cyclops/data/base/HAMTTest.java | 4 +- .../data/basetests/BaseImmutableMapTest.java | 162 +++++++++++++++++- 6 files changed, 216 insertions(+), 21 deletions(-) diff --git a/cyclops/src/main/java/cyclops/data/HashMap.java b/cyclops/src/main/java/cyclops/data/HashMap.java index a5462685da..7bf1c5b84a 100644 --- a/cyclops/src/main/java/cyclops/data/HashMap.java +++ b/cyclops/src/main/java/cyclops/data/HashMap.java @@ -2,6 +2,7 @@ import com.oath.cyclops.types.persistent.PersistentMap; import com.oath.cyclops.hkt.Higher2; +import cyclops.companion.Comparators; import cyclops.control.Option; import cyclops.control.Trampoline; import cyclops.function.Function3; @@ -230,10 +231,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null) return false; - if(o instanceof HashMap){ - HashMap hashMap = (HashMap) o; - return Objects.equals(map, hashMap.map); - } + if(o instanceof PersistentMap){ PersistentMap m = (PersistentMap)o; return equalTo(m); @@ -244,7 +242,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(map); + return map.streamNaturalOrder().foldLeft(0,(acc,t2)-> acc+t2.hashCode()); } public static HashMap narrow(HashMap map) { diff --git a/cyclops/src/main/java/cyclops/data/base/HAMT.java b/cyclops/src/main/java/cyclops/data/base/HAMT.java index 3757e74b27..a040f5bca7 100644 --- a/cyclops/src/main/java/cyclops/data/base/HAMT.java +++ b/cyclops/src/main/java/cyclops/data/base/HAMT.java @@ -2,6 +2,7 @@ import com.oath.cyclops.matching.Deconstruct.Deconstruct2; +import cyclops.companion.Comparators; import cyclops.control.Option; import cyclops.data.ImmutableList; import cyclops.data.LazySeq; @@ -59,6 +60,9 @@ default Node minus( K key){ int size(); LazySeq> lazyList(); ReactiveSeq> stream(); + default ReactiveSeq> streamNaturalOrder(){ + return stream(); + } } @@ -284,7 +288,12 @@ public ReactiveSeq> stream() { return bucket.stream(); } - public String toString(){ + @Override + public ReactiveSeq> streamNaturalOrder() { + return stream().sorted(Comparators.naturalOrderIdentityComparator()); + } + + public String toString(){ return "[COLLISION : h:"+hash+","+bucket.toString()+"]"; } } diff --git a/cyclops/src/test/java/cyclops/data/HashMapTest.java b/cyclops/src/test/java/cyclops/data/HashMapTest.java index a0ab4655bc..c5b72d7f5f 100644 --- a/cyclops/src/test/java/cyclops/data/HashMapTest.java +++ b/cyclops/src/test/java/cyclops/data/HashMapTest.java @@ -1,6 +1,10 @@ package cyclops.data; import com.oath.cyclops.types.persistent.PersistentMap; +import cyclops.control.Option; +import cyclops.data.tuple.Tuple2; +import lombok.AllArgsConstructor; +import lombok.ToString; import org.hamcrest.MatcherAssert; import org.junit.Test; @@ -8,7 +12,7 @@ import java.util.ArrayList; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; public class HashMapTest { @@ -18,34 +22,58 @@ public void plusSize(){ } @Test - public void add10000(){ + public void stream(){ - //19742 - long start = System.currentTimeMillis(); + } + + + @Test + public void read100_000_00(){ + + //6247 HashMap v = HashMap.empty(); + for(int i=0;i<100_000_00;i++){ v =v.put(i,i); } + ArrayList al = new ArrayList(v.size()); + long start = System.currentTimeMillis(); + for(int i=0;i<100_000_00;i++){ + Integer next = v.getOrElse(i,null); + assertNotNull(next); + al.add(next); + } + System.out.println(System.currentTimeMillis()-start); - System.out.println(v.size()); + assertThat(v.size(),equalTo(100_000_00)); + assertThat(al.size(),equalTo(100_000_00)); } @Test - public void read100_000_00(){ + public void read100_000_00Stream(){ //6247 HashMap v = HashMap.empty(); + for(int i=0;i<100_000_00;i++){ + v =v.put(i,i); + } + for(int i =0;i<100_000_00;i=i+2){ + v=v.remove(i); + } for(int i=0;i<100_000_00;i++){ v =v.put(i,i); } ArrayList al = new ArrayList(v.size()); long start = System.currentTimeMillis(); - for(int i=0;i<100_000_00;i++){ - al.add(v.getOrElse(i,null)); + for(Integer i : v.stream().map(Tuple2::_1)){ + Integer next = v.getOrElse(i,null); + assertNotNull(next); + al.add(next); } System.out.println(System.currentTimeMillis()-start); - System.out.println(v.size()); + assertThat(v.size(),equalTo(100_000_00)); + assertThat(al.size(),equalTo(100_000_00)); } @Test public void read100_000_00PC(){ @@ -81,4 +109,8 @@ public void add10000PCol(){ public void removeMissingKey(){ MatcherAssert.assertThat(HashMap.of(1,"a",2,"b").removeAll(0),equalTo(HashMap.of(1,"a",2,"b"))); } + + + } + diff --git a/cyclops/src/test/java/cyclops/data/ImmutableHashMapTest.java b/cyclops/src/test/java/cyclops/data/ImmutableHashMapTest.java index 35676e24cf..fda5d15d25 100644 --- a/cyclops/src/test/java/cyclops/data/ImmutableHashMapTest.java +++ b/cyclops/src/test/java/cyclops/data/ImmutableHashMapTest.java @@ -34,4 +34,4 @@ protected ImmutableMap fromMap(Map map) { HashMap x = HashMap.fromStream(s); return x; } -} \ No newline at end of file +} diff --git a/cyclops/src/test/java/cyclops/data/base/HAMTTest.java b/cyclops/src/test/java/cyclops/data/base/HAMTTest.java index bcf56c23ce..309a425762 100644 --- a/cyclops/src/test/java/cyclops/data/base/HAMTTest.java +++ b/cyclops/src/test/java/cyclops/data/base/HAMTTest.java @@ -167,7 +167,7 @@ public void orderCompare() { - @Test @Ignore + @Test //@Ignore public void problemBitsetNode(){ Node[] nodes = new Node[2]; nodes[0] = new HAMT.ValueNode<>(-1,-1,-1); @@ -183,7 +183,7 @@ public void problemBitsetNode(){ System.out.println("index "+ node.bitpos(minusOne.hashCode(), 5)); System.out.println("index "+ node.bitpos(minusOne.hashCode(), 10)); - // assertTrue(node.get(10,minusOne.hashCode(),minusOne).isPresent()); + assertTrue(node.get(10,minusOne.hashCode(),minusOne).isPresent()); assertTrue(node.get(10,thirtyOne.hashCode(),thirtyOne).isPresent()); } diff --git a/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java b/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java index 40731b5cff..fb6e9a11e7 100644 --- a/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java +++ b/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java @@ -7,19 +7,23 @@ import cyclops.control.Option; import cyclops.data.ImmutableMap; import cyclops.reactive.ReactiveSeq; +import lombok.AllArgsConstructor; +import lombok.ToString; import org.junit.Test; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public abstract class BaseImmutableMapTest { @@ -28,6 +32,78 @@ public abstract class BaseImmutableMapTest { protected abstract ImmutableMap of(K k1,V v1,K k2, V v2); protected abstract ImmutableMap fromMap(Map hello); + @Test + public void insertionOrder() { + ImmutableMap map1 = empty(); + ImmutableMap map2 = empty(); + for (int i = 0; i <= 100_000; i++) { + map1 = map1.put(i, i); + map2 = map2.put(100_000 - i, 100_000 - i); + } + assertEquals(map1,map2); + assertEquals(map1.hashCode(), map2.hashCode()); + + } + @AllArgsConstructor + @ToString + static class Collider{ + int id; + int hash; + + public int hashCode(){ + return hash; + } + + public boolean equals(Object o){ + if(o instanceof Collider){ + Collider c =(Collider)o; + return c.id==id; + + } + return false; + } + } + + @Test + public void collisions() { + ImmutableMap map1 = empty(); + ImmutableMap map2 = empty(); + int size = 10; + for (int i = 0; i <= size; i++) { + map1 = map1.put(new Collider(i,i%10), i); + map2 = map2.put(new Collider(size - i,(size - i)%10), size - i); + } + assertEquals(map1,map2); + assertEquals(map1.hashCode(), map2.hashCode()); + } + @Test + public void equalsTest() { + + assertThat(empty(),equalTo(cyclops.data.HashMap.empty())); + assertThat(this.empty(),equalTo(cyclops.data.TreeMap.empty(Comparator.naturalOrder()))); + assertThat(this.of(1,2),equalTo(cyclops.data.TreeMap.of(Comparator.naturalOrder(),1,2))); + assertThat(this.of(1,2),equalTo(cyclops.data.HashMap.of(1,2))); + assertThat(this.of(1,2,3,4),equalTo(cyclops.data.TreeMap.of(Comparator.naturalOrder(),1,2,3,4))); + assertThat(this.of(1,2,3,4),equalTo(cyclops.data.HashMap.of(1,2,3,4))); + + } + @Test + public void creation(){ + assertThat(empty().put("hello","world"),equalTo(of("hello","world"))); + } + @Test + public void lookup() { + assertThat(empty().put(1, 2).get(1),equalTo(Option.some(2))); + assertThat(empty().put(1, 2).get(2),equalTo(Option.none())); + assertThat(empty().put(1, 2).containsKey(1),equalTo(true)); + assertThat(empty().put(1, 2).containsKey(2),equalTo(false)); + assertThat(empty().put(1, 2).containsValue(1),equalTo(false)); + assertThat(empty().put(1, 2).containsValue(2),equalTo(true)); + assertThat(empty().put(1, 2).contains(Tuple.tuple(1,2)),equalTo(true)); + assertThat(empty().put(1, 2).contains(Tuple.tuple(4,5)),equalTo(false)); + + } + @Test public void keys() { @@ -52,6 +128,7 @@ public void values(){ assertThat(allValues,hasItem("b")); } + @Test public void removeMissingKey(){ assertThat(of(1,"a",2,"b").remove(0),equalTo(of(1,"a",2,"b"))); @@ -59,6 +136,41 @@ public void removeMissingKey(){ assertThat(of(1,"a",2,"b").remove(5),equalTo(of(1,"a",2,"b"))); assertThat(of(1,"a",2,"b").removeAll(5),equalTo(of(1,"a",2,"b"))); } + @Test + public void removeAllKeys() { + ImmutableMap test = this.empty().put(1, 10).put(2, 20).put(3, 20); + assertThat(test.removeAllKeys(Vector.of(1, 2)),equalTo(of(3,20))); + assertThat(test.removeAllKeys(Vector.of()),equalTo(test)); + assertThat(test.removeAllKeys(Vector.of(100,200,300)),equalTo(test)); + + } + @Test + public void removeAll() { + ImmutableMap test = this.empty().put(1, 10).put(2, 20).put(3, 20); + assertThat(test.removeAll(1, 2),equalTo(of(3,20))); + assertThat(test.removeAll(),equalTo(test)); + assertThat(test.removeAll(100,200,300),equalTo(test)); + + } + @Test + public void removeAllKeysEmpty() { + ImmutableMap test = this.empty(); + assertThat(test.removeAllKeys(Vector.of(1, 2)),equalTo(test)); + assertThat(test.removeAllKeys(Vector.of()),equalTo(test)); + assertThat(test.removeAllKeys(Vector.of(100,200,300)),equalTo(test)); + + } + @Test + public void removeAllEmpty() { + ImmutableMap test = this.empty(); + assertThat(test.removeAll(1, 2),equalTo(test)); + assertThat(test.removeAll(),equalTo(test)); + assertThat(test.removeAll(100,200,300),equalTo(test)); + + } + + + @Test public void addRemove(){ for(int i=0;i<100_00;i++) { @@ -102,10 +214,12 @@ public void toSeq(){ @Test public void onEmpty(){ assertThat(empty().onEmpty(Tuple.tuple("hello",10)).get("hello"),equalTo(Option.some(10))); + assertThat(empty().put("world",20).onEmpty(Tuple.tuple("hello",10)).get("hello"),equalTo(Option.none())); } @Test public void onEmptyGet(){ assertThat(empty().onEmptyGet(()->Tuple.tuple("hello",10)).get("hello"),equalTo(Option.some(10))); + assertThat(empty().put("world",20).onEmptyGet(()->Tuple.tuple("hello",10)).get("hello"),equalTo(Option.none())); } @Test public void onEmptyThrow(){ @@ -268,6 +382,47 @@ public void add50000Entries(){ putAndCompare(map); } + + @Test + public void bipeek(){ + + AtomicReference> key = new AtomicReference<>(Vector.empty()); + AtomicReference> value = new AtomicReference<>(Vector.empty()); + ImmutableMap map = empty(); + HashSet keys = HashSet.empty(); + HashSet values = HashSet.empty(); + for(int i=0;i<80;i++){ + map = map.put(i,i*2); + keys = keys.add(i); + values = values.add(i*2); + } + ImmutableMap map2 = map.bipeek(k->key.updateAndGet(v->v.append(k)), v->value.updateAndGet(vec->vec.append(v))); + + assertThat(map2.keys().toHashSet(),equalTo(keys)); + assertThat(map2.values().toHashSet(),equalTo(values)); + + + } + @Test + public void peek(){ + + AtomicReference> key = new AtomicReference<>(Vector.empty()); + AtomicReference> value = new AtomicReference<>(Vector.empty()); + ImmutableMap map = empty(); + + HashSet values = HashSet.empty(); + for(int i=0;i<80;i++){ + map = map.put(i,i*2); + values = values.add(i*2); + } + ImmutableMap map2 = map.peek(v->value.updateAndGet(vec->vec.append(v))); + + + assertThat(map2.values().toHashSet(),equalTo(values)); + + + } + @Test public void map(){ ImmutableMap map = empty(); @@ -275,6 +430,7 @@ public void map(){ map = map.put(i,i*2); } ImmutableMap map2 = map.bimap(k->k*2,v->v*10); + assertThat(map2.stream().map(t->t._1()).sumInt(i->i),equalTo(map.stream().map(t->t._1()).sumInt(i->i)*2)); assertThat(map2.stream().map(t->t._2()).sumInt(i->i),equalTo(map.stream().map(t->t._2()).sumInt(i->i)*10)); From ce02f27238a91b0316a8914f78277f0b4282b7b7 Mon Sep 17 00:00:00 2001 From: johnmcclean Date: Sun, 16 Dec 2018 14:34:51 +0000 Subject: [PATCH 2/4] bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8d69f61b2b..57dc4f400f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version = 10.1.0 +version = 10.1.1 agronaVersion=0.9.27 reactiveStreamsVersion=1.0.2 reactorVersion=3.2.3.RELEASE From 4b56077887d7edef007e179d170554283256c035 Mon Sep 17 00:00:00 2001 From: johnmcclean Date: Sun, 16 Dec 2018 16:21:36 +0000 Subject: [PATCH 3/4] fix bug --- cyclops/src/main/java/cyclops/control/LazyEither.java | 2 +- .../java/cyclops/control/futureOverwriteIssue/Processor.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cyclops/src/main/java/cyclops/control/LazyEither.java b/cyclops/src/main/java/cyclops/control/LazyEither.java index 0bf14782d3..4bb5d66330 100644 --- a/cyclops/src/main/java/cyclops/control/LazyEither.java +++ b/cyclops/src/main/java/cyclops/control/LazyEither.java @@ -1150,7 +1150,7 @@ public ReactiveSeq stream() { @Override public Maybe filter(final Predicate test) { - return Maybe.fromIterable(this).filter(test); + return Maybe.fromPublisher(this).filter(test); } diff --git a/cyclops/src/test/java/cyclops/control/futureOverwriteIssue/Processor.java b/cyclops/src/test/java/cyclops/control/futureOverwriteIssue/Processor.java index 11e79e729a..f8a7890062 100644 --- a/cyclops/src/test/java/cyclops/control/futureOverwriteIssue/Processor.java +++ b/cyclops/src/test/java/cyclops/control/futureOverwriteIssue/Processor.java @@ -36,7 +36,7 @@ public static enum Error { @Test public void testFailure() throws MalformedURLException { - for(int i=0;i<10000;i++) { + for(int i=0;i<100;i++) { System.out.println("*********** " + i); URLDataFileMetadata failingURL = new URLDataFileMetadata(10l, "url", new URL("http://oath23232.com")); @@ -87,7 +87,8 @@ public void testSleepingFilterSwap() throws MalformedURLException { SleepingURLDataFileMetadata slowUrl = new SleepingURLDataFileMetadata(10l, "url", new URL("https://www.rte.ie/")); long start = System.currentTimeMillis(); - Option x = proc.processUsersFiles(user, NonEmptyList.of(slowUrl)).swap().filter(i -> true); + Option x = proc.processUsersFiles(user, NonEmptyList.of(slowUrl)) + .swap().filter(i -> true); System.out.println(System.currentTimeMillis() + " Blocked? "); System.out.println(System.currentTimeMillis() + " No... "); From 7d81aca0773decabb2aa043b99bf5af560164a27 Mon Sep 17 00:00:00 2001 From: johnmcclean Date: Sun, 16 Dec 2018 23:11:54 +0000 Subject: [PATCH 4/4] fix tests --- .../types/persistent/PersistentMap.java | 22 ++++++++++-------- .../src/main/java/cyclops/data/HashMap.java | 4 ++-- .../main/java/cyclops/data/ImmutableMap.java | 6 ++++- .../src/main/java/cyclops/data/TreeMap.java | 9 +++++--- .../src/main/java/cyclops/data/TrieMap.java | 4 ++-- .../cyclops/data/base/HashedPatriciaTrie.java | 8 +++++++ .../java/cyclops/data/base/RedBlackTree.java | 1 + .../cyclops/data/ImmutableTreeMapTest.java | 14 +++++++++++ .../test/java/cyclops/data/base/HAMTTest.java | 23 +------------------ .../data/basetests/BaseImmutableMapTest.java | 7 +++++- 10 files changed, 58 insertions(+), 40 deletions(-) diff --git a/cyclops/src/main/java/com/oath/cyclops/types/persistent/PersistentMap.java b/cyclops/src/main/java/com/oath/cyclops/types/persistent/PersistentMap.java index 20fa5175d3..0d8fcf27c6 100644 --- a/cyclops/src/main/java/com/oath/cyclops/types/persistent/PersistentMap.java +++ b/cyclops/src/main/java/com/oath/cyclops/types/persistent/PersistentMap.java @@ -7,8 +7,10 @@ import java.util.Iterator; import java.util.Objects; +import java.util.function.Predicate; import java.util.function.Supplier; + public interface PersistentMap extends Iterable> { PersistentMap put(K key, V value); @@ -37,20 +39,22 @@ default ReactiveSeq> stream(){ return ReactiveSeq.fromIterable(this); } + default boolean allMatch(Predicate> c){ + return !stream().filterNot(c) + .findFirst() + .isPresent(); + } default boolean equalTo(PersistentMap map){ if(size()!=map.size()) return false; - Iterator> iterator = iterator(); - while(iterator.hasNext()){ - Tuple2 t2 = iterator.next(); - if(!Objects.equals(map.getOrElse(t2._1(),null),t2._2())){ - return false; - } - - } - return true; + return allMatch(map::contains); + } + + default boolean contains(Tuple2 t) { + return get(t._1()).filter(v-> Objects.equals(v,t._2())).isPresent(); + } default MapView mapView(){ return new MapView.Impl<>(this); } diff --git a/cyclops/src/main/java/cyclops/data/HashMap.java b/cyclops/src/main/java/cyclops/data/HashMap.java index 8fcf3ed69c..21e7fa6d2c 100644 --- a/cyclops/src/main/java/cyclops/data/HashMap.java +++ b/cyclops/src/main/java/cyclops/data/HashMap.java @@ -157,7 +157,7 @@ public HashMap remove(K key) { public HashMap removeAll(K... keys) { HAMT.Node cur = map; for(K key : keys){ - cur = map.minus(0,key.hashCode(),key); + cur = cur.minus(0,key.hashCode(),key); } return new HashMap<>(cur); } @@ -211,7 +211,7 @@ public HashMap putAll(PersistentMap map) { public HashMap removeAllKeys(Iterable keys) { HashMap res = this; for(K e : keys){ - res = this.remove(e); + res = res.remove(e); } return res; } diff --git a/cyclops/src/main/java/cyclops/data/ImmutableMap.java b/cyclops/src/main/java/cyclops/data/ImmutableMap.java index beeeef3264..ebc7461a57 100644 --- a/cyclops/src/main/java/cyclops/data/ImmutableMap.java +++ b/cyclops/src/main/java/cyclops/data/ImmutableMap.java @@ -30,6 +30,10 @@ public interface ImmutableMap extends Iterable>, OnEmptySwitch,ImmutableMap> { + @Override + default boolean allMatch(final Predicate> c) { + return Folds.super.allMatch(c); + } ImmutableMap put(K key, V value); ImmutableMap put(Tuple2 keyAndValue); @@ -180,7 +184,7 @@ default ImmutableMap notNull(){ @Override default ImmutableMap peek(Consumer c) { - return (HashMap)Transformable.super.peek(c); + return (ImmutableMap)Transformable.super.peek(c); } diff --git a/cyclops/src/main/java/cyclops/data/TreeMap.java b/cyclops/src/main/java/cyclops/data/TreeMap.java index 3c60167bf8..4591e0665b 100644 --- a/cyclops/src/main/java/cyclops/data/TreeMap.java +++ b/cyclops/src/main/java/cyclops/data/TreeMap.java @@ -185,7 +185,7 @@ public TreeMap remove(K key) { public TreeMap removeAll(K... keys) { RedBlackTree.Tree cur = map; for(K key : keys){ - cur = map.minus(key); + cur = cur.minus(key); } return new TreeMap<>(cur, comparator); } @@ -327,10 +327,13 @@ public boolean equals(Object o) { return equalTo(m); } return false; + } - @Override + + + @Override public int hashCode() { - return Objects.hash(map); + return map.stream().foldLeft(0,(acc,t2)-> acc+t2.hashCode()); } } diff --git a/cyclops/src/main/java/cyclops/data/TrieMap.java b/cyclops/src/main/java/cyclops/data/TrieMap.java index 45244d6744..8c8b1d482e 100644 --- a/cyclops/src/main/java/cyclops/data/TrieMap.java +++ b/cyclops/src/main/java/cyclops/data/TrieMap.java @@ -77,7 +77,7 @@ public TrieMap remove(K key) { public TrieMap removeAll(K[] keys) { HashedPatriciaTrie.Node cur = map; for(K key : keys){ - cur = map.minus(key.hashCode(),key); + cur = cur.minus(key.hashCode(),key); } return new TrieMap<>(cur); } @@ -196,6 +196,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(map); + return map.streamNaturalOrder().foldLeft(0,(acc,t2)-> acc+t2.hashCode()); } } diff --git a/cyclops/src/main/java/cyclops/data/base/HashedPatriciaTrie.java b/cyclops/src/main/java/cyclops/data/base/HashedPatriciaTrie.java index 5978748494..9c9cc55325 100644 --- a/cyclops/src/main/java/cyclops/data/base/HashedPatriciaTrie.java +++ b/cyclops/src/main/java/cyclops/data/base/HashedPatriciaTrie.java @@ -3,6 +3,7 @@ import com.oath.cyclops.matching.Deconstruct.Deconstruct1; import com.oath.cyclops.matching.Deconstruct.Deconstruct2; import com.oath.cyclops.matching.Sealed4; +import cyclops.companion.Comparators; import cyclops.control.Option; import cyclops.data.LazySeq; @@ -55,6 +56,9 @@ interface Node extends Sealed4,SingleNode,CollisionNod Node minus(int hash, K key); ReactiveSeq> stream(); + default ReactiveSeq> streamNaturalOrder(){ + return stream(); + } } @@ -308,6 +312,10 @@ public R fold(Function, ? extends R> fn1, Function>> unapply() { return Tuple.tuple(bucket); } + @Override + public ReactiveSeq> streamNaturalOrder() { + return stream().sorted(Comparators.naturalOrderIdentityComparator()); + } } static final class ArrayNode implements Node, Deconstruct1[]> { diff --git a/cyclops/src/main/java/cyclops/data/base/RedBlackTree.java b/cyclops/src/main/java/cyclops/data/base/RedBlackTree.java index 8687e94a13..a764b8a7de 100644 --- a/cyclops/src/main/java/cyclops/data/base/RedBlackTree.java +++ b/cyclops/src/main/java/cyclops/data/base/RedBlackTree.java @@ -194,6 +194,7 @@ else if (compRes==0) @Override public Tree plus(K key, V value) { + int compRes = comp.compare(this.key,key); if (compRes>0) { return balance(isBlack, left.plus(key, value), right, this.key, this.value); diff --git a/cyclops/src/test/java/cyclops/data/ImmutableTreeMapTest.java b/cyclops/src/test/java/cyclops/data/ImmutableTreeMapTest.java index 4c4946c7e8..38c055dcc0 100644 --- a/cyclops/src/test/java/cyclops/data/ImmutableTreeMapTest.java +++ b/cyclops/src/test/java/cyclops/data/ImmutableTreeMapTest.java @@ -11,6 +11,7 @@ import java.util.stream.Stream; import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -48,4 +49,17 @@ public void add50000Entries(){ putAndCompare(map); } + @Test + public void insertionOrder() { + ImmutableMap map1 = empty(); + ImmutableMap map2 = empty(); + for (int i = 0; i <= 1000; i++) { + map1 = map1.put(i, i); + map2 = map2.put(1000 - i, 1000 - i); + } + assertEquals(map1,map2); + assertEquals(map1.hashCode(), map2.hashCode()); + + } + } diff --git a/cyclops/src/test/java/cyclops/data/base/HAMTTest.java b/cyclops/src/test/java/cyclops/data/base/HAMTTest.java index 6dccd076f8..ca4632475e 100644 --- a/cyclops/src/test/java/cyclops/data/base/HAMTTest.java +++ b/cyclops/src/test/java/cyclops/data/base/HAMTTest.java @@ -225,28 +225,7 @@ public void replace12() throws Exception { } - - - @Test //@Ignore - public void problemBitsetNode(){ - Node[] nodes = new Node[2]; - nodes[0] = new HAMT.ValueNode<>(-1,-1,-1); - nodes[1] = new HAMT.ValueNode<>(31,31,31); - BitsetNode node = new BitsetNode( new Long(Long.parseLong("10000000000000000000000000000001", 2)).intValue(), - 2,nodes); - - System.out.println("index "+ node.bitpos(thirtyOne.hashCode(), 0)); - System.out.println("index "+ node.bitpos(thirtyOne.hashCode(), 5)); - System.out.println("index "+ node.bitpos(thirtyOne.hashCode(), 10)); - - System.out.println("index "+ node.bitpos(minusOne.hashCode(), 0)); - System.out.println("index "+ node.bitpos(minusOne.hashCode(), 5)); - System.out.println("index "+ node.bitpos(minusOne.hashCode(), 10)); - - assertTrue(node.get(10,minusOne.hashCode(),minusOne).isPresent()); - assertTrue(node.get(10,thirtyOne.hashCode(),thirtyOne).isPresent()); - } - + diff --git a/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java b/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java index 374f03e2d1..7c7e1fb133 100644 --- a/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java +++ b/cyclops/src/test/java/cyclops/data/basetests/BaseImmutableMapTest.java @@ -44,7 +44,7 @@ public void insertionOrder() { } @AllArgsConstructor @ToString - static class Collider{ + static class Collider implements Comparable{ int id; int hash; @@ -60,6 +60,11 @@ public boolean equals(Object o){ } return false; } + + @Override + public int compareTo(Collider o) { + return id-o.id; + } } @Test