Ranides Atterwim 9 år sedan
förälder
incheckning
d2e6c5d923

+ 40 - 0
assira.drafts/src/main/java/net/ranides/assira/collections/map/IndexMap.java

@@ -0,0 +1,40 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public interface IndexMap<V> {
+
+    IndexMap<V> index(String name, Comparator<? super V> index);
+    
+    IndexQuery<V> find();
+
+    IndexQuery<V> find(Comparator<? super V> index, V value);
+
+    IndexQuery<V> find(String index, V value);
+
+    void put(V value);
+
+    void put(Collection<? extends V> values);
+
+    void remove(Comparator<? super V> index, V value);
+
+    void remove(String index, V value);
+    
+    void remove(V value);
+    
+    void removeAll(Collection<V> values);
+
+    void clear();
+
+}

+ 43 - 0
assira.drafts/src/main/java/net/ranides/assira/collections/map/IndexQuery.java

@@ -0,0 +1,43 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map;
+
+import java.util.Comparator;
+import java.util.function.Consumer;
+import net.ranides.assira.collection.query.CQuery;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public interface IndexQuery<V> extends CQuery<V> {
+
+    IndexQuery<V> eq(Comparator<? super V> index, V value);
+
+    IndexQuery<V> eq(String index, V value);
+    
+
+    IndexQuery<V> gt(Comparator<? super V> index, V value);
+
+    IndexQuery<V> gt(String index, V value);
+    
+    
+    IndexQuery<V> lt(Comparator<? super V> index, V value);
+
+    IndexQuery<V> lt(String index, V value);
+    
+
+    IndexQuery<V> in(Comparator<? super V> index, V begin, V end);
+
+    IndexQuery<V> in(String index, V begin, V end);
+
+    
+    void remove();
+
+    void update(Consumer<? super V> consumer);
+    
+}

+ 63 - 0
assira.drafts/src/main/java/net/ranides/assira/collections/map/impl/AIndexMap.java

@@ -0,0 +1,63 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map.impl;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.function.Consumer;
+import net.ranides.assira.collections.map.IndexMap;
+import net.ranides.assira.collections.map.IndexQuery;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public abstract class AIndexMap<V> implements IndexMap<V> {
+    
+    
+    @Override
+    public final IndexQuery<V> find(Comparator<? super V> index, V value) {
+        return find().eq(index, value);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public final IndexQuery<V> find(String index, V value) {
+        return find().eq(indexForName(index), value);
+    }
+    
+    @Override
+    public final void put(Collection<? extends V> values) {
+        for(V value : values) {
+            put(value);
+        }
+    }
+    
+    @Override
+    public final void remove(Comparator<? super V> index, V value) {
+        find(index, value).remove();
+    }
+    
+    @Override
+    public final void remove(String index, V value) {
+        find(index, value).remove();
+    }
+
+    @Override
+    public void removeAll(Collection<V> values) {
+        for(V item : values) {
+            remove(item);
+        }
+    }
+    
+    protected abstract Comparator indexForName(String name);
+
+    protected abstract void update(V value, Consumer<? super V> consumer);
+    
+    protected abstract void updateAll();
+    
+}

+ 49 - 0
assira.drafts/src/main/java/net/ranides/assira/collections/map/impl/AIndexQuery.java

@@ -0,0 +1,49 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import net.ranides.assira.collections.map.IndexQuery;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import net.ranides.assira.collection.query.CQueryAbstract;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public abstract class AIndexQuery<V> extends CQueryAbstract<V> implements IndexQuery<V> {
+    
+    protected abstract AIndexMap<V> parent();
+    
+    @Override
+    public final IndexQuery<V> eq(String index, V value) {
+        return eq(parent().indexForName(index), value);
+    }
+    
+    @Override
+    public final IndexQuery<V> lt(String index, V value) {
+        return lt(parent().indexForName(index), value);
+    }
+    
+    @Override
+    public final IndexQuery<V> gt(String index, V value) {
+        return gt(parent().indexForName(index), value);
+    }
+    
+    @Override
+    public final IndexQuery<V> in(String index, V begin, V end) {
+        return in(parent().indexForName(index), begin, end);
+    }
+    
+    @Override
+    public void update(Consumer<? super V> consumer) {
+        collect(Collectors.toList()).forEach(v -> parent().update(v, consumer));
+    }
+    
+}

+ 223 - 0
assira.drafts/src/main/java/net/ranides/assira/collections/map/impl/CIndexTreeMap.java

@@ -0,0 +1,223 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import net.ranides.assira.collection.sets.ASortedSet;
+import net.ranides.assira.collection.sets.RBTreeMultiSet;
+import net.ranides.assira.collections.map.IndexMap;
+import net.ranides.assira.collections.map.IndexQuery;
+import net.ranides.assira.generic.CompareUtils;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class CIndexTreeMap<V> extends AIndexMap<V> {
+    
+    private final Map<String, Comparator> name2cmp = new HashMap<>();
+    
+    private final Map<Comparator, ASortedSet<V>> indexes = new HashMap<>();
+
+    @Override
+    public IndexMap<V> index(String name, Comparator<? super V> index) {
+        RBTreeMultiSet<V> set = new RBTreeMultiSet<>(index);
+        indexes.put(index, set);
+        name2cmp.put(name, index);
+        for(V item : values()) {
+            set.add(item);
+        }
+        return this;
+    }
+
+    @Override
+    protected Comparator indexForName(String name) {
+        return name2cmp.get(name);
+    }
+
+    @Override
+    protected void update(V value, Consumer<? super V> consumer) {
+        remove(value);
+        consumer.accept(value);
+        put(value);
+    }
+    
+    @Override
+    public void remove(V value) {
+        for(SortedSet<V> index : indexes.values()) {
+            iremove(index, value);
+        }
+    }
+    
+    void iremove(SortedSet<V> set, V value) {
+        Comparator<? super V> c = set.comparator();
+        Iterator<V> i = set.headSet(value).iterator();
+        while(i.hasNext()) {
+            V item = i.next();
+            if(c.compare(item, value) !=0) {
+                return;
+            }
+            if(CompareUtils.equals(item,value)) {
+                i.remove();
+                return;
+            }
+        }
+    }
+    
+    @Override
+    protected void updateAll() {
+        List<V> items = new ArrayList<>(values());
+        for(SortedSet<V> index : indexes.values()) {
+            index.clear();
+            index.addAll(items);
+        }
+    }
+
+    
+    @Override
+    public IndexQuery<V> find() {
+        return new CHQuery();
+    }
+
+    @Override
+    public void put(V value) {
+        for(SortedSet<V> index : indexes.values()) {
+            index.add(value);
+        }
+    }
+
+    @Override
+    public void clear() {
+        for(SortedSet<V> index : indexes.values()) {
+            index.clear();
+        }
+    }
+    
+    private ASortedSet<V> values() {
+        return indexes.values().iterator().next();
+    }
+
+    
+    private final class CHQuery extends AIndexQuery<V> {
+        
+        private final List<Supplier<Collection<V>>> selectors;
+
+        public CHQuery() {
+            this.selectors = Collections.emptyList();
+        }
+        
+        public CHQuery(CHQuery query, Supplier<Collection<V>> selector) {
+            this.selectors = new ArrayList<>(query.selectors.size()+1);
+            this.selectors.addAll(query.selectors);
+            this.selectors.add(selector);
+        }
+        
+        @Override
+        protected AIndexMap<V> parent() {
+            return CIndexTreeMap.this;
+        }
+
+        @Override
+        public Stream<V> stream() {
+            return select().stream();
+        }
+
+        @Override
+        public int size() {
+            return select().size();
+        }
+
+        @Override
+        public Iterator<V> iterator() {
+            return select().iterator();
+        }
+
+        @Override
+        public IndexQuery<V> eq(Comparator<? super V> index, V value) {
+            return new CHQuery(this, () -> indexes.get(index).getAll(value));
+        }
+
+        @Override
+        public IndexQuery<V> gt(Comparator<? super V> index, V value) {
+            ASortedSet<V> set = indexes.get(index);
+            return new CHQuery(this, () -> {
+                V last = set.after(value);
+                return last==null ? Collections.emptyList() : set.tailSet(last);
+            });
+        }
+
+        @Override
+        public IndexQuery<V> lt(Comparator<? super V> index, V value) {
+            return new CHQuery(this, () -> indexes.get(index).headSet(value));
+        }
+
+        @Override
+        public IndexQuery<V> in(Comparator<? super V> index, V begin, V end) {
+            return new CHQuery(this, () -> indexes.get(index).subSet(begin, end));
+        }
+
+        @Override
+        public void remove() {
+            removeAll(select());
+        }
+        
+        private List<V> select() {
+            int psize = 0;
+            Collection<V> prim = null;
+            List<Collection<V>> sec = new ArrayList<>(selectors.size()-1);
+            for(Supplier<Collection<V>> s : selectors) {
+                Collection<V> c = s.get();
+                int csize = c.size();
+                
+                if(psize > csize) {
+                    sec.add(prim);
+                    prim = null;
+                }
+                if(prim==null) {
+                    prim = c;
+                    psize = csize;
+                } else {
+                    sec.add(c);
+                }
+            }
+            
+            if(prim==null) {
+                return Collections.emptyList();
+            }
+            
+            List<V> out = new ArrayList<>(prim.size());
+            for(V item : prim) {
+                if(selected(sec,item)) {
+                    out.add(item);
+                }
+            }
+            return out;
+        }
+        
+        private boolean selected(List<Collection<V>> sec, V item) {
+            for(Collection<V> s : sec) {
+                if(!s.contains(item)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        
+    }
+    
+}

+ 194 - 0
assira.drafts/src/test/java/net/ranides/assira/collections/map/impl/CIndexTreeMapTest.java

@@ -0,0 +1,194 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+package net.ranides.assira.collections.map.impl;
+
+import net.ranides.assira.collections.map.IndexMap;
+import net.ranides.assira.generic.CompareUtils;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class CIndexTreeMapTest {
+    
+    @Test
+    public void testBasic() {
+        
+        IndexMap<Person> db = new CIndexTreeMap<>();
+        db.index("name", (a,b) -> CompareUtils.cmp(a.name, b.name));
+        db.index("surname", (a,b) -> CompareUtils.cmp(a.surname, b.surname));
+        db.index("age", (a,b) -> CompareUtils.cmp(a.age, b.age));
+        
+        db.put(new Person("Tom", "A", 17));
+        db.put(new Person("Tom", "B", 23));
+        db.put(new Person("Joe", "A", 20));
+        db.put(new Person("Helene", "C", 19));
+        db.put(new Person("Andrew", "S", 23));
+        db.put(new Person("Helene", "C", 23));
+        db.put(new Person("George", "T", 17));
+        db.put(new Person("Peter", "A", 17));
+        
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("name", new Person("Helene", "", 0))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("age", new Person("", "", 23))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("name", new Person("Helene", "", 0))
+            .eq("age", new Person("", "", 23))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("age", new Person("", "", 17))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("surname", new Person("", "A", 3))
+            .eq("age", new Person("", "", 17))
+            .sort()    
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .gt("age", new Person("", "", 17))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .gt("age", new Person("", "", 40))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .lt("age", new Person("", "", 18))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .lt("age", new Person("", "", 17))
+            .sort()
+            .list()
+        );
+        System.out.printf("RESULT = %s%n", db.find()
+            .eq("name", new Person("Helene", "", 23))
+            .lt("age", new Person("Helene", "", 23))
+            .sort()
+            .list()
+        );
+        
+        
+        
+        
+        
+        assertEquals("[{Helene C 19}, {Helene C 23}]", db.find()
+            .eq("name", new Person("Helene", "", 0))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Tom B 23}, {Helene C 23}, {Andrew S 23}]", db.find()
+            .eq("age", new Person("", "", 23))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Helene C 23}]", db.find()
+            .eq("name", new Person("Helene", "", 0))
+            .eq("age", new Person("", "", 23))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Peter A 17}, {Tom A 17}, {George T 17}]", db.find()
+            .eq("age", new Person("", "", 17))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Peter A 17}, {Tom A 17}]", db.find()
+            .eq("surname", new Person("", "A", 0))
+            .eq("age", new Person("", "", 17))
+            .sort()    
+            .list()
+            .toString()
+        );
+        assertEquals("[{Joe A 20}, {Tom B 23}, {Helene C 19}, {Helene C 23}, {Andrew S 23}]", db.find()
+            .gt("age", new Person("", "", 17))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[]", db.find()
+            .gt("age", new Person("", "", 40))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Peter A 17}, {Tom A 17}, {George T 17}]", db.find()
+            .lt("age", new Person("", "", 18))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[]", db.find()
+            .lt("age", new Person("", "", 17))
+            .sort()
+            .list()
+            .toString()
+        );
+        assertEquals("[{Helene C 19}]", db.find()
+            .eq("name", new Person("Helene", "", 23))
+            .lt("age", new Person("Helene", "", 23))
+            .sort()
+            .list()
+            .toString()
+        );
+    }
+    
+    private static final class Person implements Comparable<Person> {
+        
+        public final String name;
+        public final String surname;
+        public final int age;
+
+        public Person(String name, String surname, int age) {
+            this.name = name;
+            this.surname = surname;
+            this.age = age;
+        }
+
+        @Override
+        public String toString() {
+            return "{" + name + " " + surname + " " + age + "}";
+        }
+
+        @Override
+        public int compareTo(Person that) {
+            int c;
+            c = CompareUtils.cmp(this.surname, that.surname);
+            if(c!=0) {
+                return c;
+            }
+            c = CompareUtils.cmp(this.name, that.name);
+            if(c!=0) {
+                return c;
+            }
+            c = CompareUtils.cmp(this.age, that.age);
+            return c;
+        }
+        
+    }
+    
+}