|
|
@@ -4,7 +4,7 @@
|
|
|
* @license WTFPL
|
|
|
* @url http://ranides.net/projects/assira.drafts
|
|
|
*/
|
|
|
-package net.ranides.assira.collection.maps;
|
|
|
+package net.ranides.assira.index;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
@@ -17,11 +17,15 @@ import java.util.Map;
|
|
|
import java.util.Map.Entry;
|
|
|
import java.util.SortedMap;
|
|
|
import java.util.SortedSet;
|
|
|
+import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
import java.util.function.Supplier;
|
|
|
-import java.util.stream.Stream;
|
|
|
+import net.ranides.assira.collection.maps.ASortedMap;
|
|
|
+import net.ranides.assira.collection.maps.MultiMap;
|
|
|
+import net.ranides.assira.collection.maps.RBTreeMultiMap;
|
|
|
import net.ranides.assira.collection.sets.ASortedSet;
|
|
|
import net.ranides.assira.collection.sets.IdentSet;
|
|
|
+import net.ranides.assira.collection.sets.MultiSet;
|
|
|
import net.ranides.assira.collection.sets.RBTreeMultiSet;
|
|
|
|
|
|
import net.ranides.assira.generic.CompareUtils;
|
|
|
@@ -30,7 +34,7 @@ import net.ranides.assira.generic.CompareUtils;
|
|
|
*
|
|
|
* @author Ranides Atterwim <ranides@gmail.com>
|
|
|
*/
|
|
|
-public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
+public class IQueryMapTree<V> extends IQueryAbstract.IQMap<V> {
|
|
|
|
|
|
private final Map<String, Comparator> name2sindex = new HashMap<>();
|
|
|
|
|
|
@@ -41,7 +45,7 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
private final Map<Function, RBTreeMultiMap<Object, V>> mindexes = new HashMap<>();
|
|
|
|
|
|
@Override
|
|
|
- public IndexMap<V> index(String name, Comparator<V> index) {
|
|
|
+ public IQueryMap<V> index(String name, Comparator<V> index) {
|
|
|
RBTreeMultiSet<V> set = new RBTreeMultiSet<>(index);
|
|
|
cindexes.put(index, set);
|
|
|
name2sindex.put(name, index);
|
|
|
@@ -52,7 +56,7 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public <T> IndexMap<V> index(String name, Function<V, T> index) {
|
|
|
+ public <T> IQueryMap<V> index(String name, Function<V, T> index) {
|
|
|
RBTreeMultiMap<Object,V> map = new RBTreeMultiMap<>();
|
|
|
mindexes.put(index, map);
|
|
|
name2mindex.put(name, index);
|
|
|
@@ -62,22 +66,10 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- @Override
|
|
|
- protected <T> Function<V, T> mindex(String name) {
|
|
|
- return name2mindex.get(name);
|
|
|
- }
|
|
|
-
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- @Override
|
|
|
- protected Comparator<V> sindex(String name) {
|
|
|
- return name2sindex.get(name);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public void remove(V value) {
|
|
|
for(SortedSet<V> index : cindexes.values()) {
|
|
|
- IndexTreeMap.this.iremove(index, value);
|
|
|
+ IQueryMapTree.this.iremove(index, value);
|
|
|
}
|
|
|
for(SortedMap<Object,V> index : mindexes.values()) {
|
|
|
iremove(index, value);
|
|
|
@@ -131,11 +123,10 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
|
|
|
@Override
|
|
|
- public AIndexQuery<V> find() {
|
|
|
- return new CHQuery();
|
|
|
+ public IQueryAbstract<V> find() {
|
|
|
+ return new TreeQuery();
|
|
|
}
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
@@ -156,6 +147,9 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
for(SortedSet<V> index : cindexes.values()) {
|
|
|
index.clear();
|
|
|
}
|
|
|
+ for(SortedMap<Object,V> index : mindexes.values()) {
|
|
|
+ index.clear();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private Collection<V> values() {
|
|
|
@@ -164,6 +158,16 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
}
|
|
|
return cindexes.values().iterator().next();
|
|
|
}
|
|
|
+
|
|
|
+ private static <T> Collection<T> tail(ASortedMap<Object, T> mi, Object value) {
|
|
|
+ Object last = after(mi,value);
|
|
|
+ return last==null ? Collections.emptyList() : mi.tailMap(last).values();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static <T> Collection<T> tail(ASortedSet<T> ci, T value) {
|
|
|
+ T last = after(ci,value);
|
|
|
+ return last==null ? Collections.emptyList() : ci.tailSet(last);
|
|
|
+ }
|
|
|
|
|
|
private static Object after(ASortedMap<Object, ?> map, Object value) {
|
|
|
Comparator<Object> cmp = CompareUtils.comparator();
|
|
|
@@ -189,168 +193,134 @@ public class IndexTreeMap<V> extends AIndexMap<V> {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- private Collection<V> merge(Collection<V> a, Collection<V> b) {
|
|
|
- Collection<V> out = new IdentSet<>(a.size() + b.size());
|
|
|
+ private static <T> Collection<T> merge(Collection<T> a, Collection<T> b) {
|
|
|
+ Collection<T> out = new IdentSet<>(a.size() + b.size());
|
|
|
out.addAll(a);
|
|
|
out.addAll(b);
|
|
|
return out;
|
|
|
}
|
|
|
|
|
|
|
|
|
- private final class CHQuery extends AIndexQuery<V> {
|
|
|
+ private final class TreeQuery extends IQueryAbstract<V> {
|
|
|
|
|
|
private final List<Supplier<Collection<V>>> selectors;
|
|
|
|
|
|
private final boolean require;
|
|
|
|
|
|
- public CHQuery() {
|
|
|
+ public TreeQuery() {
|
|
|
this.selectors = Collections.emptyList();
|
|
|
this.require = true;
|
|
|
}
|
|
|
|
|
|
- public CHQuery(CHQuery query, Supplier<Collection<V>> selector) {
|
|
|
+ public TreeQuery(TreeQuery query, Supplier<Collection<V>> selector) {
|
|
|
this.selectors = new ArrayList<>(query.selectors.size()+1);
|
|
|
this.selectors.addAll(query.selectors);
|
|
|
this.selectors.add(selector);
|
|
|
this.require = true;
|
|
|
}
|
|
|
|
|
|
- public CHQuery(CHQuery query, boolean require) {
|
|
|
+ public TreeQuery(TreeQuery query, boolean require) {
|
|
|
this.selectors = new ArrayList<>(query.selectors);
|
|
|
this.require = require;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
@Override
|
|
|
- public IndexQuery<V> require() {
|
|
|
- return new CHQuery(this, true);
|
|
|
+ protected <T> Function<V, T> mindex(String name) {
|
|
|
+ return name2mindex.get(name);
|
|
|
}
|
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
@Override
|
|
|
- public IndexQuery<V> optional() {
|
|
|
- return new CHQuery(this, false);
|
|
|
+ protected Comparator<V> sindex(String name) {
|
|
|
+ return name2sindex.get(name);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@Override
|
|
|
- protected AIndexMap<V> parent() {
|
|
|
- return IndexTreeMap.this;
|
|
|
+ public IQuery<V> require() {
|
|
|
+ return new TreeQuery(this, true);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Stream<V> stream() {
|
|
|
- return select().stream();
|
|
|
+ public IQuery<V> optional() {
|
|
|
+ return new TreeQuery(this, false);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public int size() {
|
|
|
- return select().size();
|
|
|
+ public IQuery<V> eq(Comparator<V> index, V value) {
|
|
|
+ RBTreeMultiSet<V> ci = cindexes.get(index);
|
|
|
+ return select(ci, () -> ci.getAll(value));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Iterator<V> iterator() {
|
|
|
- return select().iterator();
|
|
|
+ public <T> IQuery<V> eq(Function<V, T> index, T value) {
|
|
|
+ RBTreeMultiMap<Object, V> mi = mindexes.get(index);
|
|
|
+ return select(mi, () -> mi.getAll(value));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public IndexQuery<V> eq(Comparator<V> index, V value) {
|
|
|
+ public IQuery<V> gt(Comparator<V> index, V value) {
|
|
|
RBTreeMultiSet<V> ci = cindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> ci.getAll(value));
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- return merge(ci.getAll(value), ci.getAll(null));
|
|
|
- });
|
|
|
- }
|
|
|
+ return select(ci, () -> tail(ci, value));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@Override
|
|
|
- public <T> IndexQuery<V> eq(Function<V, T> index, T value) {
|
|
|
+ public <T> IQuery<V> gt(Function<V, T> index, T value) {
|
|
|
RBTreeMultiMap<Object, V> mi = mindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> mi.getAll(value));
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- return merge(mi.getAll(value), mi.getAll(null));
|
|
|
- });
|
|
|
- }
|
|
|
+ return select(mi, () -> tail(mi, value));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public IndexQuery<V> gt(Comparator<V> index, V value) {
|
|
|
+ public IQuery<V> lt(Comparator<V> index, V value) {
|
|
|
RBTreeMultiSet<V> ci = cindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- V last = after(ci,value);
|
|
|
- return last==null ? Collections.emptyList() : ci.tailSet(last);
|
|
|
- });
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- V last = after(ci,value);
|
|
|
- return last==null ? ci.getAll(null) : merge(ci.tailSet(last), ci.getAll(null));
|
|
|
- });
|
|
|
- }
|
|
|
+ return select(ci, () -> ci.headSet(value));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public <T> IndexQuery<V> gt(Function<V, T> index, T value) {
|
|
|
+ public <T> IQuery<V> lt(Function<V, T> index, T value) {
|
|
|
RBTreeMultiMap<Object, V> mi = mindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- Object last = after(mi,value);
|
|
|
- return last==null ? Collections.emptyList() : mi.tailMap(last).values();
|
|
|
- });
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> {
|
|
|
- Object last = after(mi,value);
|
|
|
- return last==null ? mi.getAll(null) : merge(mi.tailMap(last).values(), mi.getAll(null));
|
|
|
- });
|
|
|
- }
|
|
|
+ return select(mi, () -> mi.headMap(value).values());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public IndexQuery<V> lt(Comparator<V> index, V value) {
|
|
|
+ public IQuery<V> in(Comparator<V> index, V begin, V end) {
|
|
|
RBTreeMultiSet<V> ci = cindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> ci.headSet(value));
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> merge(ci.headSet(value), ci.getAll(null)));
|
|
|
- }
|
|
|
+ return select(ci, () -> ci.subSet(begin, end));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public <T> IndexQuery<V> lt(Function<V, T> index, T value) {
|
|
|
+ public <T> IQuery<V> in(Function<V, T> index, T begin, T end) {
|
|
|
RBTreeMultiMap<Object, V> mi = mindexes.get(index);
|
|
|
- if(require) {
|
|
|
- return new CHQuery(this, () -> mi.headMap(value).values());
|
|
|
- } else {
|
|
|
- return new CHQuery(this, () -> merge(mi.headMap(value).values(), mi.getAll(null)));
|
|
|
- }
|
|
|
+ return select(mi, () -> mi.subMap(begin, end).values());
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@Override
|
|
|
- public IndexQuery<V> in(Comparator<V> index, V begin, V end) {
|
|
|
- RBTreeMultiSet<V> ci = cindexes.get(index);
|
|
|
+ public void update(Consumer<? super V> consumer) {
|
|
|
+ select().forEach(v -> IQueryMapTree.this.update(v, consumer));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void remove() {
|
|
|
+ removeAll(select());
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T> IQuery<V> select(MultiSet<V> ci, Supplier<Collection<V>> f) {
|
|
|
if(require) {
|
|
|
- return new CHQuery(this, () -> ci.subSet(begin, end));
|
|
|
+ return new TreeQuery(this, f);
|
|
|
} else {
|
|
|
- return new CHQuery(this, () -> merge(ci.subSet(begin, end), ci.getAll(null)));
|
|
|
+ return new TreeQuery(this, () -> merge(f.get(), ci.getAll(null)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public <T> IndexQuery<V> in(Function<V, T> index, T begin, T end) {
|
|
|
- RBTreeMultiMap<Object, V> mi = mindexes.get(index);
|
|
|
+ private <T> IQuery<V> select(MultiMap<Object, V> mi, Supplier<Collection<V>> f) {
|
|
|
if(require) {
|
|
|
- return new CHQuery(this, () -> mi.subMap(begin, end).values());
|
|
|
+ return new TreeQuery(this, f);
|
|
|
} else {
|
|
|
- return new CHQuery(this, () -> merge(mi.subMap(begin, end).values(), mi.getAll(null)));
|
|
|
+ return new TreeQuery(this, () -> merge(f.get(), mi.getAll(null)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void remove() {
|
|
|
- removeAll(select());
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
protected Collection<V> select() {
|
|
|
int psize = 0;
|