fdd03bca5e2213bf91f067dd3e4340e5ccf16b24
[yangtools.git] / third-party / triemap / src / main / java / org / opendaylight / yangtools / triemap / MutableIterator.java
1 /*
2  * (C) Copyright 2017 Pantheon Technologies, s.r.o. and others.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.opendaylight.yangtools.triemap;
17
18 import static com.google.common.base.Preconditions.checkState;
19
20 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21 import java.util.Map.Entry;
22
23 /**
24  * Specialized immutable iterator for use with {@link ImmutableEntrySet}.
25  *
26  * @author Robert Varga
27  *
28  * @param <K> the type of entry keys
29  * @param <V> the type of entry values
30  */
31 final class MutableIterator<K, V> extends AbstractIterator<K, V> {
32     private final MutableTrieMap<K, V> mutable;
33
34     private Entry<K, V> lastReturned;
35
36     MutableIterator(final MutableTrieMap<K, V> map) {
37         super(map.immutableSnapshot());
38         this.mutable = map;
39     }
40
41     @Override
42     public void remove() {
43         checkState(lastReturned != null);
44         mutable.remove(lastReturned.getKey());
45         lastReturned = null;
46     }
47
48     @Override
49     Entry<K, V> wrapEntry(final Entry<K, V> entry) {
50         lastReturned = entry;
51         return new MutableEntry<>(mutable, entry);
52     }
53
54     /**
55      * A mutable view of an entry in the map. Since the backing map is concurrent, its {@link #getValue()} and
56      * {@link #setValue(Object)} methods cannot guarantee consistency with the base map and may produce surprising
57      * results when the map is concurrently modified, either directly or via another entry/iterator.
58      *
59      * The behavior is similar to what Java 8's ConcurrentHashMap does, which is probably the most consistent handling
60      * of this case without requiring expensive and revalidation.
61      */
62     private static final class MutableEntry<K, V> implements Entry<K, V> {
63         private final MutableTrieMap<K, V> map;
64         private final Entry<K, V> delegate;
65
66         @SuppressWarnings("null")
67         private V newValue = null;
68
69         MutableEntry(final MutableTrieMap<K, V> map, final Entry<K, V> delegate) {
70             this.map = map;
71             this.delegate = delegate;
72         }
73
74         @Override
75         public K getKey() {
76             return delegate.getKey();
77         }
78
79         /**
80          * {@inheritDoc}
81          *
82          * @implSpec
83          * This implementation returns the most uptodate value we have observed via this entry. It does not reflect
84          * concurrent modifications, nor does it throw {@link IllegalStateException} if the entry is removed.
85          */
86         @Override
87         public V getValue() {
88             return newValue != null ? newValue : delegate.getValue();
89         }
90
91         /**
92          * {@inheritDoc}
93          *
94          * @implSpec
95          * This implementation returns the most uptodate value we have observed via this entry. It does not reflect
96          * concurrent modifications, nor does it throw {@link IllegalStateException} if the entry is removed.
97          */
98         @Override
99         public V setValue(final V value) {
100             final V ret = getValue();
101             map.put(getKey(), value);
102             newValue = value;
103             return ret;
104         }
105
106         @Override
107         public int hashCode() {
108             return EntryUtil.hash(getKey(), getValue());
109         }
110
111         @SuppressFBWarnings(value = "EQ_UNUSUAL",  justification = "Equality handled by utility methods")
112         @Override
113         public boolean equals(final Object o) {
114             return EntryUtil.equal(o, getKey(), getValue());
115         }
116
117         @Override
118         public String toString() {
119             return EntryUtil.string(getKey(), getValue());
120         }
121     }
122 }