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 com.google.common.base.VerifyException;
21 * Similar to Scala's ListMap, this is a single-linked list of set of map entries. Aside from the Set contract, this
22 * class fulfills the requirements for an immutable map entryset.
24 * @author Robert Varga
26 * @param <K> the type of keys
27 * @param <V> the type of values
29 abstract class LNodeEntries<K, V> extends LNodeEntry<K, V> {
30 private static final class Single<K, V> extends LNodeEntries<K, V> {
31 Single(final K k, final V v) {
36 LNodeEntries<K, V> next() {
41 private static final class Multiple<K, V> extends LNodeEntries<K, V> {
42 // Modified during remove only, otherwise final
43 LNodeEntries<K, V> next;
45 // Used in remove() only
46 Multiple(final LNodeEntries<K, V> e) {
47 this(e.getKey(), e.getValue(), null);
50 Multiple(final K k, final V v, final LNodeEntries<K, V> next) {
56 LNodeEntries<K, V> next() {
61 LNodeEntries(final K k, final V v) {
65 static <K,V> LNodeEntries<K, V> map(final K k1, final V v1, final K k2, final V v2) {
66 return new Multiple<>(k1, v1, new Single<>(k2, v2));
70 * Return the remainder of this list. Useful for implementing Iterator-like contract. Null indicates there are no
73 * @return Remainder of this list, or null if nothing remains
75 abstract LNodeEntries<K, V> next();
77 final LNodeEntry<K, V> findEntry(final Equivalence<? super K> equiv, final K key) {
78 // We do not perform recursion on purpose here, so we do not run out of stack if the key hashing fails.
79 LNodeEntries<K, V> entry = this;
81 if (equiv.equivalent(entry.getKey(), key)) {
86 } while (entry != null);
91 final LNodeEntries<K,V> insert(final K key, final V value) {
92 return new Multiple<>(key, value, this);
95 final LNodeEntries<K, V> replace(final LNodeEntry<K, V> entry, final V v) {
96 final LNodeEntries<K, V> removed;
97 return (removed = remove(entry)) == null ? new Single<>(entry.getKey(), v)
98 : new Multiple<>(entry.getKey(), v, removed);
101 final LNodeEntries<K, V> remove(final LNodeEntry<K, V> entry) {
106 // This will result in a list with a long tail, i.e last entry storing explicit null. Overhead is amortized
107 // against the number of entries. We do not retain chains shorter than two, so the worst-case overhead is
108 // half-a-reference for an entry.
109 final Multiple<K, V> ret = new Multiple<>(this);
111 Multiple<K, V> last = ret;
112 LNodeEntries<K, V> cur = next();
113 while (cur != null) {
114 // We cannot use equals() here, as it is wired to key equality and we must never compare entries based on
115 // that property. This method is intended to remove a known reference, so identity is what we want.
117 last.next = cur.next();
121 final Multiple<K, V> tmp = new Multiple<>(cur);
127 throw new VerifyException(String.format("Failed to find entry %s", entry));