/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2013 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package erjang.m.ets;
import java.util.Iterator;
import java.util.Map;
import com.trifork.clj_ds.APersistentMap;
import com.trifork.clj_ds.IMapEntry;
import com.trifork.clj_ds.IPersistentCollection;
import com.trifork.clj_ds.IPersistentMap;
import com.trifork.clj_ds.ISeq;
import com.trifork.clj_ds.PersistentHashMap;
import com.trifork.clj_ds.PersistentTreeMap;
import com.trifork.clj_ds.RT;
@SuppressWarnings({ "serial", "unchecked" })
public class EPersistentInsertionOrderedMap<K,V> extends APersistentMap<K,V> {
public static class EIterator<K, V> implements Iterator<Entry<K, V>> {
private Iterator<? extends java.util.Map.Entry<? extends Object, ? extends Map.Entry<K, V>>> it;
public EIterator(
Iterator<? extends java.util.Map.Entry<? extends Object, ? extends Map.Entry<K, V>>> it) {
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public java.util.Map.Entry<K, V> next() {
return it.next().getValue();
}
@Override
public void remove() {
it.remove();
}
}
private final IPersistentMap<Long, Rec<K,V>> iorder;
private final IPersistentMap<K, Rec<K,V>> korder;
private final long ins;
@SuppressWarnings({ "rawtypes" })
public static EPersistentInsertionOrderedMap EMPTY = new EPersistentInsertionOrderedMap(0, PersistentTreeMap.EMPTY, PersistentHashMap.EMPTY);
private EPersistentInsertionOrderedMap(long ins, IPersistentMap<Long,Rec<K,V>> iorder, IPersistentMap<K,Rec<K,V>> keyorder)
{
this.ins = ins+1;
this.iorder = iorder;
this.korder = keyorder;
}
static class Rec<K,V> implements IMapEntry<K, V>, Map.Entry<K, V> {
private K key;
private V value;
private Long ins;
Rec(Long ins, K key, V value) {
this.ins = ins;
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
@Override
public K key() {
return key;
}
@Override
public V val() {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
IMapEntry<K, V> o = (IMapEntry<K, V>) obj;
return o.key().equals(key) && o.val().equals(value);
}
}
Rec<K,V> rec(K key, V value) {
return new Rec<K,V>(ins, key, value);
}
@Override
public IPersistentMap<K, V> assoc(K key, V value) {
Rec<K,V> nrec = rec(key, value);
Rec<K,V> orec = korder.valAt(key);
IPersistentMap<Long, Rec<K,V>> i = iorder;
if (orec != null) {
try {
i = i.without(orec.ins);
} catch (Exception e) {
// ignore //
}
}
i = i.assoc(nrec.ins, nrec);
IPersistentMap<K, Rec<K, V>> k = korder.assoc(key, nrec);
return make(i, k);
}
private IPersistentMap<K, V> make(IPersistentMap<Long, Rec<K, V>> i,
IPersistentMap<K, Rec<K, V>> k) {
return new EPersistentInsertionOrderedMap<K,V>(ins, i, k);
}
@Override
public IPersistentMap<K, V> assocEx(K key, V value) throws Exception {
Rec<K,V> nrec = rec(key, value);
Rec<K,V> orec = korder.valAt(key);
IPersistentMap<Long, Rec<K,V>> i = iorder;
if (orec != null) {
try {
i = i.without(orec.ins);
} catch (Exception e) {
// ignore //
}
}
IPersistentMap<K, Rec<K, V>> k = korder.assocEx(key, nrec);
i = i.assocEx(nrec.ins, nrec);
return make(i, k);
}
@Override
public Iterator<java.util.Map.Entry<K, V>> iteratorFrom(K key) {
return new EIterator<K,V>( korder.iteratorFrom(key) );
}
@Override
public Iterator<java.util.Map.Entry<K, V>> reverseIterator() {
return new EIterator<K,V>( iorder.reverseIterator() );
}
@Override
public Iterator<java.util.Map.Entry<K, V>> iterator() {
return new EIterator<K,V>( iorder.iterator() );
}
@Override
public IPersistentMap<K, V> without(K key) throws Exception {
Rec<K,V> orec = korder.valAt(key);
IPersistentMap<K, Rec<K, V>> k = korder;
IPersistentMap<Long, Rec<K,V>> i = iorder;
if (orec != null) {
try {
k = k.without(key);
i = i.without(orec.ins);
} catch (Exception e) {
// ignore //
}
}
return make(i, k);
}
@Override
public boolean containsKey(Object arg0) {
return korder.containsKey((K) arg0);
}
@Override
public IMapEntry<K, V> entryAt(final K key) {
Rec<K,V> rec = korder.valAt(key);
if (rec == null) return null;
return rec;
}
@Override
public int count() {
return korder.count();
}
@Override
public IPersistentCollection<IMapEntry<K, V>> empty() {
return EPersistentInsertionOrderedMap.EMPTY;
}
@Override
public ISeq<IMapEntry<K, V>> seq() {
ISeq<IMapEntry<Long, Rec<K, V>>> seq = iorder.seq();
if (seq == null) return null;
return new ESeq<K,V>(seq);
}
static class ESeq<K,V> implements ISeq<IMapEntry<K, V>> {
ISeq<IMapEntry<Long, Rec<K,V>>> iseq;
ESeq(ISeq<IMapEntry<Long, Rec<K,V>>> iseq) { this.iseq = iseq; }
@Override
public int count() {
return iseq.count();
}
@Override
public IPersistentCollection<IMapEntry<K, V>> empty() {
return EPersistentInsertionOrderedMap.EMPTY;
}
@Override
public boolean equiv(Object arg0) {
return equals(arg0);
}
@Override
public ISeq<IMapEntry<K, V>> seq() {
return this;
}
@Override
public ISeq<IMapEntry<K, V>> cons(IMapEntry<K, V> arg0) {
return RT.cons(arg0, seq());
}
@Override
public IMapEntry<K, V> first() {
IMapEntry<Long, Rec<K, V>> first = iseq.first();
if (first == null) return null;
return first.getValue();
}
// @SuppressWarnings("unchecked")
@Override
public ISeq<IMapEntry<K, V>> more() {
ISeq<IMapEntry<Long, Rec<K, V>>> more = iseq.more();
if (more == null) return null;
return new ESeq<K,V>(more);
}
@Override
public ISeq<IMapEntry<K, V>> next() {
ISeq<IMapEntry<Long, Rec<K, V>>> next = iseq.next();
if (next == null) return null;
return new ESeq<K,V>(next);
}
}
@Override
public V valAt(K arg0) {
Rec<K, V> rec = korder.valAt(arg0);
if (rec == null) return null;
return rec.value;
}
@Override
public V valAt(K arg0, V arg1) {
V v = valAt(arg0);
if (v == null) v = arg1;
return v;
}
@SuppressWarnings("rawtypes")
@Override
public void putAll(Map m) {
throw new UnsupportedOperationException();
}
}