Forráskód Böngészése

resolve #120 - new: CrossSet

Ranides Atterwim 1 éve
szülő
commit
247ec626fb

+ 83 - 0
assira.commons/src/main/java/net/ranides/assira/collection/sets/AVLCrossSet.java

@@ -0,0 +1,83 @@
+package net.ranides.assira.collection.sets;
+
+import net.ranides.assira.collection.maps.AVLTreeMultiMap;
+import net.ranides.assira.collection.maps.MultiMap;
+import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.generic.Pair;
+
+import java.util.Comparator;
+
+public class AVLCrossSet<K1, K2> extends AVLTreeSet<Pair<K1, K2>> implements CrossSet<K1, K2> {
+
+    private final Comparator<? super K1> comparator1;
+    private final Comparator<? super K2> comparator2;
+
+    public AVLCrossSet() {
+        super();
+        this.comparator1 = null;
+        this.comparator2 = null;
+    }
+
+    public AVLCrossSet(Comparator<? super K1> comparator1, Comparator<? super K2> comparator2) {
+        super((a,b) -> {
+            int cmp1 = CompareUtils.cmp(comparator1, a.getFirst(), b.getFirst());
+            return cmp1 != 0 ? cmp1 : CompareUtils.cmp(comparator2, a.getSecond(), b.getSecond());
+        });
+        this.comparator1 = comparator1;
+        this.comparator2 = comparator2;
+    }
+
+    protected final int compare1(K1 key1, K1 key2) {
+        try {
+            return CompareUtils.cmp(comparator1, key1, key2);
+        } catch(ClassCastException ex){
+            // "unchecked" generic methods could pass something strange here
+            return -1;
+        }
+    }
+
+    protected final int compare2(K2 key1, K2 key2) {
+        try {
+            return CompareUtils.cmp(comparator2, key1, key2);
+        } catch(ClassCastException ex){
+            // "unchecked" generic methods could pass something strange here
+            return -1;
+        }
+    }
+
+    @Override
+    public boolean contains(K1 key1, K2 key2) {
+        return contains(Pair.of(key1, key2));
+    }
+
+    @Override
+    public boolean add(K1 key1, K2 key2) {
+        return add(Pair.of(key1, key2));
+    }
+
+    @Override
+    public boolean remove(K1 key1, K2 key2) {
+        return remove(Pair.of(key1, key2));
+    }
+
+    @Override
+    public MultiSet<K2> reduceFirst() {
+        MultiSet<K2> result = new AVLTreeMultiSet<>(this::compare2);
+        forEach((key1, key2) -> result.add(key2));
+        return result;
+    }
+
+    @Override
+    public MultiSet<K1> reduceSecond() {
+        MultiSet<K1> result = new AVLTreeMultiSet<>(this::compare1);
+        forEach((key1, key2) -> result.add(key1));
+        return result;
+    }
+
+    @Override
+    public MultiMap<K1, K2> asMap() {
+        MultiMap<K1, K2> result = new AVLTreeMultiMap<>(this::compare1);
+        forEach((key1, key2) -> result.put(key1, key2));
+        return result;
+    }
+}

+ 83 - 0
assira.commons/src/main/java/net/ranides/assira/collection/sets/RBCrossSet.java

@@ -0,0 +1,83 @@
+package net.ranides.assira.collection.sets;
+
+import net.ranides.assira.collection.maps.MultiMap;
+import net.ranides.assira.collection.maps.RBTreeMultiMap;
+import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.generic.Pair;
+
+import java.util.Comparator;
+
+public class RBCrossSet<K1, K2> extends RBTreeSet<Pair<K1, K2>> implements CrossSet<K1, K2> {
+
+    private final Comparator<? super K1> comparator1;
+    private final Comparator<? super K2> comparator2;
+
+    public RBCrossSet() {
+        super();
+        this.comparator1 = null;
+        this.comparator2 = null;
+    }
+
+    public RBCrossSet(Comparator<? super K1> comparator1, Comparator<? super K2> comparator2) {
+        super((a,b) -> {
+            int cmp1 = CompareUtils.cmp(comparator1, a.getFirst(), b.getFirst());
+            return cmp1 != 0 ? cmp1 : CompareUtils.cmp(comparator2, a.getSecond(), b.getSecond());
+        });
+        this.comparator1 = comparator1;
+        this.comparator2 = comparator2;
+    }
+
+    protected final int compare1(K1 key1, K1 key2) {
+        try {
+            return CompareUtils.cmp(comparator1, key1, key2);
+        } catch(ClassCastException ex){
+            // "unchecked" generic methods could pass something strange here
+            return -1;
+        }
+    }
+
+    protected final int compare2(K2 key1, K2 key2) {
+        try {
+            return CompareUtils.cmp(comparator2, key1, key2);
+        } catch(ClassCastException ex){
+            // "unchecked" generic methods could pass something strange here
+            return -1;
+        }
+    }
+
+    @Override
+    public boolean contains(K1 key1, K2 key2) {
+        return contains(Pair.of(key1, key2));
+    }
+
+    @Override
+    public boolean add(K1 key1, K2 key2) {
+        return add(Pair.of(key1, key2));
+    }
+
+    @Override
+    public boolean remove(K1 key1, K2 key2) {
+        return remove(Pair.of(key1, key2));
+    }
+
+    @Override
+    public MultiSet<K2> reduceFirst() {
+        MultiSet<K2> result = new RBTreeMultiSet<>(this::compare2);
+        forEach((key1, key2) -> result.add(key2));
+        return result;
+    }
+
+    @Override
+    public MultiSet<K1> reduceSecond() {
+        MultiSet<K1> result = new RBTreeMultiSet<>(this::compare1);
+        forEach((key1, key2) -> result.add(key1));
+        return result;
+    }
+
+    @Override
+    public MultiMap<K1, K2> asMap() {
+        MultiMap<K1, K2> result = new RBTreeMultiMap<>(this::compare1);
+        forEach((key1, key2) -> result.put(key1, key2));
+        return result;
+    }
+}

+ 79 - 0
assira.core/src/main/java/net/ranides/assira/collection/sets/CrossSet.java

@@ -0,0 +1,79 @@
+/*
+ *  @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.collection.sets;
+
+import net.ranides.assira.collection.maps.MultiMap;
+import net.ranides.assira.generic.Pair;
+
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * two-dimensional set.
+ *
+ * Its behaviour is similar to Set, but it takes two keys instead of just one.
+ * Most of the time is equivalent to the Set with composite key.
+ *
+ * It offers additional reduction methods, which returns one-dimensional MultiSet.
+ *
+ * @param <K1> K1
+ * @param <K2> K2
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ */
+public interface CrossSet<K1, K2> extends Set<Pair<K1, K2>> {
+
+
+    /**
+     * Checks if set contains provided key pair
+     *
+     * @param key1 key1
+     * @param key2 key2
+     * @return bool
+     */
+    boolean contains(K1 key1, K2 key2);
+
+    boolean add(K1 key1, K2 key2);
+
+    boolean remove(K1 key1, K2 key2);
+
+    /**
+     * Creates new MultiSet which contains all entries without first key.
+     * Returns MultiSet because this operation can lead to duplicated K2 keys.
+     *
+     * @return new collection
+     */
+    MultiSet<K2> reduceFirst();
+
+    /**
+     * Creates new MultiSet which contains all entries without second key.
+     * Returns MultiSet because this operation can lead to duplicated K1 keys.
+     *
+     * @return new collection
+     */
+    MultiSet<K1> reduceSecond();
+
+    /**
+     * Creates new MultiMap with content of set.
+     * Each K1 key is mapped to K2 accordingly, if (K1,K2) tuple is stored inside.
+     * Returns MultiMap because this operation can lead to duplicated K1 keys.
+     *
+     * @return new collection
+     */
+    MultiMap<K1, K2> asMap();
+
+    /**
+     * Iterates sequentially through all entries inside map.
+     * It passed to "action" three arguments: key1, key2, and value.
+     *
+     * @param action action
+     */
+    default void forEach(BiConsumer<K1, K2> action) {
+        forEach(pair -> action.accept(pair.getFirst(), pair.getSecond()));
+    }
+
+}

+ 1 - 1
assira.core/src/main/java/net/ranides/assira/generic/CompareUtils.java

@@ -325,7 +325,7 @@ public class CompareUtils {
             if (b.getClass().isInstance(a)) {
                 return -b.compareTo(a);
             }
-            return a.compareTo(LexicalCast.cast(b, a.getClass()));
+            throw new ClassCastException("Values are not Comparable: " + a + " or " + b);
         }
     }
 

+ 3 - 3
assira.g4interpreter/src/test/java/net/ranides/assira/grammar/InspectionTest.java

@@ -20,16 +20,16 @@ public class InspectionTest {
 
         G4Node tree = parser.parse("expression", "(1 + 2) * 3 + 4^2");
 
-        List<String> list1 = CQuery.from().tree(() -> tree, v -> v.children())
+        List<String> list1 = CQuery.from().tree().dfs(() -> tree, v -> v.children())
             .map(v -> v.name())
             .sort()
             .list();
-        List<String> list2 = CQuery.from().tree(() -> tree, v -> v.children())
+        List<String> list2 = CQuery.from().tree().dfs(() -> tree, v -> v.children())
             .map(v -> v.name())
             .distinct()
             .sort()
             .list();
-        List<String> list3 = CQuery.from().tree(() -> tree, v -> v.children(), v -> v.shortname().equals("number"))
+        List<String> list3 = CQuery.from().tree().dfs(() -> tree, v -> v.children(), v -> v.shortname().equals("number"))
             .map(v -> v.name())
             .distinct()
             .sort()