+/*
+ * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others.
+ *
+ * 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 org.opendaylight.yangtools.triemap;
+import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Iterator;
-import java.util.Map;
import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Optional;
/**
* Mimic immutable ListMap in Scala
- *
+ *
* @author Roman Levenstein <romixlev@gmail.com>
*
* @param <V>
*/
-abstract class ListMap<K,V> {
+final class ListMap<K, V> {
+ private final K k;
+ private final V v;
- ListMap<K,V> next;
-
- static <K,V> ListMap<K, V> map(K k, V v, ListMap<K, V> tail){
- return new Node<K, V> (k, v, tail);
- }
+ // Modified during remove0 only
+ private ListMap<K, V> next;
- static <K,V> ListMap<K, V> map(K k, V v){
- return new Node<K, V> (k, v, null);
+ private ListMap(final K k, final V v) {
+ this(k, v, null);
}
- static <K,V> ListMap<K, V> map(K k1, V v1, K k2, V v2){
- return new Node<K, V> (k1, v1, new Node<K,V>(k2,v2, null));
+ private ListMap(final K k, final V v, final ListMap<K, V> next) {
+ this.k = k;
+ this.v = v;
+ this.next = next;
}
-
- public abstract int size ();
- public abstract boolean isEmpty() ;
-
- abstract public boolean contains(K k, V v);
+ static <K,V> ListMap<K, V> map(final K k1, final V v1, final K k2, final V v2) {
+ return new ListMap<>(k1, v1, new ListMap<>(k2, v2));
+ }
- abstract public boolean contains(K key);
+ Optional<Entry<K, V>> maybeSingleton() {
+ return next != null ? Optional.empty() : Optional.of(new SimpleImmutableEntry<>(k, v));
+ }
- abstract public Option<V> get (K key);
+ int size() {
+ int sz = 1;
+ for (ListMap<?, ?> wlk = next; wlk != null; wlk = wlk.next) {
+ sz++;
+ }
+ return sz;
+ }
- abstract public ListMap<K, V> add (K key, V value);
+ Optional<V> get(final Equivalence<? super K> equiv, final K key) {
+ // We do not perform recursion on purpose here, so we do not run out of stack if the key hashing fails.
+ ListMap<K, V> head = this;
+ do {
+ if (equiv.equivalent(head.k, key)) {
+ return Optional.of(head.v);
+ }
- abstract public ListMap<K, V> remove (K key);
-
- abstract public Iterator<Map.Entry<K, V>> iterator();
+ head = head.next;
+ } while (head != null);
-
- static class EmptyListMap<K,V> extends ListMap<K, V> {
- public ListMap<K,V> add (K key, V value) {
- return ListMap.map(key, value, null);
- }
-
- public boolean contains(K k, V v) {
- return false;
- }
-
- public boolean contains(K k) {
- return false;
- }
-
- public ListMap<K,V> remove(K key) {
- return this;
- }
+ return Optional.empty();
+ }
- @Override
- public int size () {
- return 0;
- }
+ ListMap<K,V> add(final Equivalence<? super K> equiv, final K key, final V value) {
+ return new ListMap<>(key, value, remove(equiv, key));
+ }
- @Override
- public boolean isEmpty () {
- return true;
+ ListMap<K, V> remove(final Equivalence<? super K> equiv, final K key) {
+ if (!contains(equiv, key)) {
+ return this;
}
- @Override
- public Option<V> get (K key) {
- return Option.makeOption (null);
- }
+ return remove0(key);
+ }
- @Override
- public Iterator<Entry<K, V>> iterator () {
- return new EmptyListMapIterator<K, V> ();
- }
-
- static class EmptyListMapIterator<K,V> implements Iterator<Entry<K, V>> {
-
- @Override
- public boolean hasNext () {
- return false;
+ private boolean contains(final Equivalence<? super K> equiv, final K key) {
+ // We do not perform recursion on purpose here, so we do not run out of stack if the key hashing fails.
+ ListMap<K, V> head = this;
+ do {
+ if (equiv.equivalent(head.k, key)) {
+ return true;
}
+ head = head.next;
+ } while (head != null);
- @Override
- public Entry<K, V> next () {
- return null;
+ return false;
+ }
+
+ private ListMap<K, V> remove0(final K key) {
+ ListMap<K, V> n = this;
+ ListMap<K, V> ret = null;
+ ListMap<K, V> lastN = null;
+ while (n != null) {
+ if (key.equals(n.k)) {
+ n = n.next;
+ continue;
}
- @Override
- public void remove () {
- throw new RuntimeException("Operation not supported");
+ if (ret != null) {
+ lastN.next = new ListMap<>(n.k, n.v);
+ lastN = lastN.next;
+ } else {
+ ret = new ListMap<>(n.k, n.v);
+ lastN = ret;
}
-
+ n = n.next;
}
+ return ret;
}
-
- static class Node<K,V> extends ListMap<K, V> {
- final K k;
- final V v;
-
- Node(K k, V v, ListMap<K,V> next) {
- this.k = k;
- this.v = v;
- this.next = next;
- }
-
- public ListMap<K,V> add (K key, V value) {
- return ListMap.map(key, value, remove (key));
- }
-
- public boolean contains(K k, V v) {
- if(k.equals (this.k) && v.equals (this.v))
- return true;
- else if(next != null)
- return next.contains (k, v);
- return false;
- }
-
- public boolean contains(K k) {
- if(k.equals (this.k))
- return true;
- else if(next != null)
- return next.contains (k);
- return false;
- }
-
- public ListMap<K,V> remove(K key) {
- if(!contains(key))
- return this;
- else
- return remove0(key);
- }
-
- private ListMap<K, V> remove0 (K key) {
- ListMap<K, V> n = this;
- ListMap<K, V> newN = null;
- ListMap<K, V> lastN = null;
- while (n != null) {
- if(n instanceof EmptyListMap) {
- newN.next = n;
- break;
- }
- Node<K, V> nn = (Node<K, V>)n;
- if (key.equals (nn.k)) {
- n = n.next;
- continue;
- } else {
- if (newN != null) {
- lastN.next = ListMap.map (nn.k, nn.v, null);
- lastN = lastN.next;
- } else {
- newN = ListMap.map (nn.k, nn.v, null);
- lastN = newN;
- }
- }
- n = n.next;
- }
- return newN;
- }
- @Override
- public int size () {
- if(next == null)
- return 1;
- else
- return 1+next.size ();
- }
+ Iterator<Entry<K, V>> iterator() {
+ return new NodeIterator<>(this);
+ }
- @Override
- public boolean isEmpty () {
- return false;
- }
+ static final class NodeIterator<K,V> implements Iterator<Entry<K, V>> {
+ private ListMap<K, V> n;
- @Override
- public Option<V> get (K key) {
- if(key.equals (k))
- return Option.makeOption (v);
- if(next != null)
- return next.get (key);
- return Option.makeOption (null);
+ NodeIterator(final ListMap<K, V> n) {
+ this.n = n;
}
-
@Override
- public Iterator<Entry<K, V>> iterator () {
- return new NodeIterator<K, V> (this);
+ public boolean hasNext() {
+ return n != null;
}
- static class NodeIterator<K,V> implements Iterator<Entry<K, V>> {
- ListMap<K, V> n;
-
- public NodeIterator (Node<K, V> n) {
- this.n = n;
- }
-
- @Override
- public boolean hasNext () {
-// return n!= null && n.next != null && !(n.next instanceof EmptyListMap);
- return n!= null && !(n instanceof EmptyListMap);
- }
-
- @Override
- public Entry<K, V> next () {
- if (n instanceof Node) {
- Node<K, V> nn = (Node<K, V>) n;
- Pair<K, V> res = new Pair<K, V> (nn.k, nn.v);
- n = n.next;
- return res;
- } else {
- return null;
- }
+ @Override
+ public Entry<K, V> next() {
+ if (n == null) {
+ throw new NoSuchElementException();
}
- @Override
- public void remove () {
- throw new RuntimeException("Operation not supported");
- }
-
+ final Entry<K, V> res = new SimpleImmutableEntry<>(n.k, n.v);
+ n = n.next;
+ return res;
}
}
}