|
@@ -14,12 +14,17 @@ import java.util.HashMap;
|
|
|
import java.util.Iterator;
|
|
import java.util.Iterator;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.Map.Entry;
|
|
|
|
|
+import java.util.SortedMap;
|
|
|
import java.util.SortedSet;
|
|
import java.util.SortedSet;
|
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Consumer;
|
|
|
import java.util.function.Supplier;
|
|
import java.util.function.Supplier;
|
|
|
import java.util.stream.Stream;
|
|
import java.util.stream.Stream;
|
|
|
|
|
+import net.ranides.assira.collection.maps.ASortedMap;
|
|
|
|
|
+import net.ranides.assira.collection.maps.RBTreeMultiMap;
|
|
|
import net.ranides.assira.collection.sets.ASortedSet;
|
|
import net.ranides.assira.collection.sets.ASortedSet;
|
|
|
import net.ranides.assira.collection.sets.RBTreeMultiSet;
|
|
import net.ranides.assira.collection.sets.RBTreeMultiSet;
|
|
|
|
|
+import net.ranides.assira.collections.map.IndexComparator;
|
|
|
import net.ranides.assira.collections.map.IndexMap;
|
|
import net.ranides.assira.collections.map.IndexMap;
|
|
|
import net.ranides.assira.collections.map.IndexQuery;
|
|
import net.ranides.assira.collections.map.IndexQuery;
|
|
|
import net.ranides.assira.generic.CompareUtils;
|
|
import net.ranides.assira.generic.CompareUtils;
|
|
@@ -30,15 +35,17 @@ import net.ranides.assira.generic.CompareUtils;
|
|
|
*/
|
|
*/
|
|
|
public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
|
|
|
|
|
|
- private final Map<String, Comparator> name2cmp = new HashMap<>();
|
|
|
|
|
|
|
+ private final Map<String, Object> name2index = new HashMap<>();
|
|
|
|
|
|
|
|
- private final Map<Comparator, ASortedSet<V>> indexes = new HashMap<>();
|
|
|
|
|
|
|
+ private final Map<Comparator, ASortedSet<V>> cindexes = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ private final Map<IndexComparator, RBTreeMultiMap<Object, V>> mindexes = new HashMap<>();
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IndexMap<V> index(String name, Comparator<? super V> index) {
|
|
|
|
|
|
|
+ public IndexMap<V> index(String name, Comparator<V> index) {
|
|
|
RBTreeMultiSet<V> set = new RBTreeMultiSet<>(index);
|
|
RBTreeMultiSet<V> set = new RBTreeMultiSet<>(index);
|
|
|
- indexes.put(index, set);
|
|
|
|
|
- name2cmp.put(name, index);
|
|
|
|
|
|
|
+ cindexes.put(index, set);
|
|
|
|
|
+ name2index.put(name, index);
|
|
|
for(V item : values()) {
|
|
for(V item : values()) {
|
|
|
set.add(item);
|
|
set.add(item);
|
|
|
}
|
|
}
|
|
@@ -46,12 +53,23 @@ public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- protected Comparator indexForName(String name) {
|
|
|
|
|
- return name2cmp.get(name);
|
|
|
|
|
|
|
+ public <T> IndexMap<V> index(String name, IndexComparator<V, T> index) {
|
|
|
|
|
+ RBTreeMultiMap<Object,V> map = new RBTreeMultiMap<>();
|
|
|
|
|
+ mindexes.put(index, map);
|
|
|
|
|
+ name2index.put(name, index);
|
|
|
|
|
+ for(V item : values()) {
|
|
|
|
|
+ map.put(index.apply(item),item);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ protected Object $index(String name) {
|
|
|
|
|
+ return name2index.get(name);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- protected void update(V value, Consumer<? super V> consumer) {
|
|
|
|
|
|
|
+ protected void $update(V value, Consumer<? super V> consumer) {
|
|
|
remove(value);
|
|
remove(value);
|
|
|
consumer.accept(value);
|
|
consumer.accept(value);
|
|
|
put(value);
|
|
put(value);
|
|
@@ -59,12 +77,15 @@ public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void remove(V value) {
|
|
public void remove(V value) {
|
|
|
- for(SortedSet<V> index : indexes.values()) {
|
|
|
|
|
- iremove(index, value);
|
|
|
|
|
|
|
+ for(SortedSet<V> index : cindexes.values()) {
|
|
|
|
|
+ $remove(index, value);
|
|
|
|
|
+ }
|
|
|
|
|
+ for(SortedMap<Object,V> index : mindexes.values()) {
|
|
|
|
|
+ CIndexTreeMap.this.$remove(index, value);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void iremove(SortedSet<V> set, V value) {
|
|
|
|
|
|
|
+ void $remove(SortedSet<V> set, V value) {
|
|
|
Comparator<? super V> c = set.comparator();
|
|
Comparator<? super V> c = set.comparator();
|
|
|
Iterator<V> i = set.headSet(value).iterator();
|
|
Iterator<V> i = set.headSet(value).iterator();
|
|
|
while(i.hasNext()) {
|
|
while(i.hasNext()) {
|
|
@@ -79,37 +100,80 @@ public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ void $remove(SortedMap<Object,V> map, V value) {
|
|
|
|
|
+ Comparator<Object> c = CompareUtils.comparator();
|
|
|
|
|
+ Iterator<Entry<Object,V>> i = map.headMap(value).entrySet().iterator();
|
|
|
|
|
+ while(i.hasNext()) {
|
|
|
|
|
+ Entry<Object,V> item = i.next();
|
|
|
|
|
+ if(c.compare(item.getKey(), value) !=0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(CompareUtils.equals(item.getValue(),value)) {
|
|
|
|
|
+ i.remove();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
- protected void updateAll() {
|
|
|
|
|
|
|
+ protected void $update() {
|
|
|
List<V> items = new ArrayList<>(values());
|
|
List<V> items = new ArrayList<>(values());
|
|
|
- for(SortedSet<V> index : indexes.values()) {
|
|
|
|
|
|
|
+ for(SortedSet<V> index : cindexes.values()) {
|
|
|
index.clear();
|
|
index.clear();
|
|
|
index.addAll(items);
|
|
index.addAll(items);
|
|
|
}
|
|
}
|
|
|
|
|
+ for(Entry<IndexComparator, RBTreeMultiMap<Object,V>> entry : mindexes.entrySet()) {
|
|
|
|
|
+ IndexComparator fun = entry.getKey();
|
|
|
|
|
+ RBTreeMultiMap<Object, V> index = entry.getValue();
|
|
|
|
|
+ index.clear();
|
|
|
|
|
+ for(V item : items) {
|
|
|
|
|
+ index.put(fun.apply(item), item);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IndexQuery<V> find() {
|
|
|
|
|
|
|
+ public AIndexQuery<V> find() {
|
|
|
return new CHQuery();
|
|
return new CHQuery();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void put(V value) {
|
|
public void put(V value) {
|
|
|
- for(SortedSet<V> index : indexes.values()) {
|
|
|
|
|
|
|
+ for(SortedSet<V> index : cindexes.values()) {
|
|
|
index.add(value);
|
|
index.add(value);
|
|
|
}
|
|
}
|
|
|
|
|
+ for(Entry<IndexComparator, RBTreeMultiMap<Object,V>> entry : mindexes.entrySet()) {
|
|
|
|
|
+ IndexComparator fun = entry.getKey();
|
|
|
|
|
+ RBTreeMultiMap<Object, V> index = entry.getValue();
|
|
|
|
|
+ index.put(fun.apply(value), value);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void clear() {
|
|
public void clear() {
|
|
|
- for(SortedSet<V> index : indexes.values()) {
|
|
|
|
|
|
|
+ for(SortedSet<V> index : cindexes.values()) {
|
|
|
index.clear();
|
|
index.clear();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private ASortedSet<V> values() {
|
|
|
|
|
- return indexes.values().iterator().next();
|
|
|
|
|
|
|
+ private Collection<V> values() {
|
|
|
|
|
+ if(cindexes.isEmpty()) {
|
|
|
|
|
+ return Collections.emptySet();
|
|
|
|
|
+ }
|
|
|
|
|
+ return cindexes.values().iterator().next();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Object after(ASortedMap<Object, V> map, Object value) {
|
|
|
|
|
+ Comparator<Object> cmp = map.comparator();
|
|
|
|
|
+ Iterator<Object> i = map.keySet().iterator(value);
|
|
|
|
|
+ while(i.hasNext()) {
|
|
|
|
|
+ Object next = i.next();
|
|
|
|
|
+ if(!CompareUtils.equals(value, next)) {
|
|
|
|
|
+ return next;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -134,49 +198,70 @@ public class CIndexTreeMap<V> extends AIndexMap<V> {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Stream<V> stream() {
|
|
public Stream<V> stream() {
|
|
|
- return select().stream();
|
|
|
|
|
|
|
+ return $select().stream();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public int size() {
|
|
public int size() {
|
|
|
- return select().size();
|
|
|
|
|
|
|
+ return $select().size();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Iterator<V> iterator() {
|
|
public Iterator<V> iterator() {
|
|
|
- return select().iterator();
|
|
|
|
|
|
|
+ return $select().iterator();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IndexQuery<V> eq(Comparator<? super V> index, V value) {
|
|
|
|
|
- return new CHQuery(this, () -> indexes.get(index).getAll(value));
|
|
|
|
|
|
|
+ public IndexQuery<V> $eq(Object index, Object value) {
|
|
|
|
|
+ if(index instanceof Comparator) {
|
|
|
|
|
+ return new CHQuery(this, () -> cindexes.get(index).getAll((V)value));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return new CHQuery(this, () -> mindexes.get(index).getAll(value));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@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);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ public IndexQuery<V> $gt(Object index, Object value) {
|
|
|
|
|
+ if(index instanceof Comparator) {
|
|
|
|
|
+ ASortedSet<V> set = cindexes.get(index);
|
|
|
|
|
+ return new CHQuery(this, () -> {
|
|
|
|
|
+ V last = set.after((V)value);
|
|
|
|
|
+ return last==null ? Collections.emptyList() : set.tailSet(last);
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ RBTreeMultiMap<Object, V> map = mindexes.get(index);
|
|
|
|
|
+ return new CHQuery(this, () -> {
|
|
|
|
|
+ Object last = after(map,value);
|
|
|
|
|
+ return last==null ? Collections.emptyList() : map.tailMap(last).values();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IndexQuery<V> lt(Comparator<? super V> index, V value) {
|
|
|
|
|
- return new CHQuery(this, () -> indexes.get(index).headSet(value));
|
|
|
|
|
|
|
+ public IndexQuery<V> $lt(Object index, Object value) {
|
|
|
|
|
+ if(index instanceof Comparator) {
|
|
|
|
|
+ return new CHQuery(this, () -> cindexes.get(index).headSet((V)value));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return new CHQuery(this, () -> mindexes.get(index).headMap(value).values());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IndexQuery<V> in(Comparator<? super V> index, V begin, V end) {
|
|
|
|
|
- return new CHQuery(this, () -> indexes.get(index).subSet(begin, end));
|
|
|
|
|
|
|
+ public IndexQuery<V> $in(Object index, Object begin, Object end) {
|
|
|
|
|
+ if(index instanceof Comparator) {
|
|
|
|
|
+ return new CHQuery(this, () -> cindexes.get(index).subSet((V)begin, (V)end));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return new CHQuery(this, () -> mindexes.get(index).subMap((V)begin, (V)end).values());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void remove() {
|
|
public void remove() {
|
|
|
- removeAll(select());
|
|
|
|
|
|
|
+ removeAll($select());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private List<V> select() {
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ protected Collection<V> $select() {
|
|
|
int psize = 0;
|
|
int psize = 0;
|
|
|
Collection<V> prim = null;
|
|
Collection<V> prim = null;
|
|
|
List<Collection<V>> sec = new ArrayList<>(selectors.size()-1);
|
|
List<Collection<V>> sec = new ArrayList<>(selectors.size()-1);
|