2 * (C) Copyright 2016 Pantheon Technologies, s.r.o. and others.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.opendaylight.yangtools.triemap;
18 import java.util.Iterator;
19 import java.util.Map.Entry;
20 import java.util.NoSuchElementException;
23 * Similar to Scala's ListMap. Stores a linked set of entries, guaranteed to contain unique entry keys.
25 * @author Robert Varga
27 * @param <K> the type of keys
28 * @param <V> the type of values
30 abstract class LNodeEntries<K, V> extends LNodeEntry<K, V> {
31 private static final class Single<K, V> extends LNodeEntries<K, V> {
32 Single(final K k, final V v) {
42 LNodeEntries<K, V> next() {
47 private static final class Multiple<K, V> extends LNodeEntries<K, V> {
48 // Modified during remove only
49 LNodeEntries<K, V> next;
51 // Used in remove() only
52 Multiple(final LNodeEntries<K, V> e) {
53 this(e.getKey(), e.getValue(), null);
56 Multiple(final K k, final V v, final LNodeEntries<K, V> next) {
67 LNodeEntries<K, V> next() {
72 LNodeEntries(final K k, final V v) {
76 static <K,V> LNodeEntries<K, V> map(final K k1, final V v1, final K k2, final V v2) {
77 return new Multiple<>(k1, v1, new Single<>(k2, v2));
80 abstract boolean isSingle();
82 abstract LNodeEntries<K, V> next();
84 final LNodeEntry<K, V> findEntry(final Equivalence<? super K> equiv, final K key) {
85 // We do not perform recursion on purpose here, so we do not run out of stack if the key hashing fails.
86 LNodeEntries<K, V> entry = this;
88 if (equiv.equivalent(entry.getKey(), key)) {
93 } while (entry != null);
98 final LNodeEntries<K,V> insert(final K key, final V value) {
99 return new Multiple<>(key, value, this);
102 final LNodeEntries<K, V> replace(final LNodeEntry<K, V> entry, final V v) {
103 final LNodeEntries<K, V> removed = remove(entry);
104 return removed == null ? new Single<>(entry.getKey(), v) : new Multiple<>(entry.getKey(), v, removed);
107 final LNodeEntries<K, V> remove(final LNodeEntry<K, V> entry) {
112 final Multiple<K, V> ret = new Multiple<>(this);
114 Multiple<K, V> last = ret;
115 LNodeEntries<K, V> cur = next();
116 while (cur != null) {
117 // We cannot use equals() here, as it is wired to key/value equality,
118 // which we really do not want.
120 last.next = cur.next();
124 final Multiple<K, V> tmp = new Multiple<>(cur);
130 throw new IllegalStateException(String.format("Entry %s not found", entry));
133 // No need to specialize these two methods, as they are invoked only from a stable LNode, at which point it is
134 // guaranteed to be a Multiple.
137 for (LNodeEntries<?, ?> wlk = next(); wlk != null; wlk = wlk.next()) {
143 final Iterator<Entry<K, V>> iterator() {
144 return new NodeIterator<>(this);
147 static final class NodeIterator<K,V> implements Iterator<Entry<K, V>> {
148 private LNodeEntries<K, V> n;
150 NodeIterator(final LNodeEntries<K, V> n) {
155 public boolean hasNext() {
160 public Entry<K, V> next() {
162 throw new NoSuchElementException();
165 final Entry<K, V> res = n;