Fire AbstractPrerequisite listeners as soon as they resolve
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementMap.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Verify.verify;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.collect.AbstractIterator;
15 import com.google.common.collect.Iterators;
16 import java.util.AbstractCollection;
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.Iterator;
20 import java.util.function.Consumer;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.eclipse.jdt.annotation.Nullable;
23
24 /**
25  * Simple integer-to-StatementContextBase map optimized for size and restricted in scope of operations. It does not
26  * implement {@link java.util.Map} for simplicity's sake.
27  *
28  * <p>
29  * Unlike other collections, this view does not detect concurrent modification. Iteration is performed in order of
30  * increasing offset. In face of concurrent modification, number of elements returned through iteration may not match
31  * the size reported via {@link Collection#size()}.
32  *
33  * @author Robert Varga
34  */
35 abstract class StatementMap extends AbstractCollection<AbstractResumedStatement<?, ?, ?>> {
36     private static final class Empty extends StatementMap {
37         private static final Iterator<AbstractResumedStatement<?, ?, ?>> EMPTY_ITERATOR;
38
39         static {
40             // This may look weird, but we really want to return two Iterator implementations from StatementMap, so that
41             // users have to deal with bimorphic invocation. Note that we want to invoke hasNext() here, as we want to
42             // initialize state to AbstractIterator.endOfData().
43             final Iterator<AbstractResumedStatement<?, ?, ?>> it = new Regular(0).iterator();
44             verify(!it.hasNext());
45             EMPTY_ITERATOR = it;
46         }
47
48         @Override
49         AbstractResumedStatement<?, ?, ?> get(final int index) {
50             return null;
51         }
52
53         @Override
54         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
55             return index == 0 ? new Singleton(obj) : new Regular(index, obj);
56         }
57
58         @Override
59         public int size() {
60             return 0;
61         }
62
63         @Override
64         StatementMap ensureCapacity(final int expectedLimit) {
65             return expectedLimit < 2 ? this : new Regular(expectedLimit);
66         }
67
68         @Override
69         public void forEach(final Consumer<? super AbstractResumedStatement<?, ?, ?>> action) {
70             // No-op
71         }
72
73         @Override
74         public Iterator<AbstractResumedStatement<?, ?, ?>> iterator() {
75             return EMPTY_ITERATOR;
76         }
77     }
78
79     private static final class Regular extends StatementMap {
80         private AbstractResumedStatement<?, ?, ?>[] elements;
81         private int size;
82
83         Regular(final int expectedLimit) {
84             elements = new AbstractResumedStatement<?, ?, ?>[expectedLimit];
85         }
86
87         Regular(final int index, final AbstractResumedStatement<?, ?, ?> object) {
88             this(index + 1, index, object);
89         }
90
91         Regular(final AbstractResumedStatement<?, ?, ?> object0, final int index,
92                 final AbstractResumedStatement<?, ?, ?> object) {
93             this(index + 1, 0, object0);
94             elements[index] = requireNonNull(object);
95             size = 2;
96         }
97
98         Regular(final int expectedLimit, final int index, final AbstractResumedStatement<?, ?, ?> object) {
99             this(expectedLimit);
100             elements[index] = requireNonNull(object);
101             size = 1;
102         }
103
104         @Override
105         AbstractResumedStatement<?, ?, ?> get(final int index) {
106             return index >= elements.length ? null : elements[index];
107         }
108
109         @Override
110         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
111             if (index < elements.length) {
112                 checkArgument(elements[index] == null);
113             } else {
114                 // FIXME: detect linear growth
115                 elements = Arrays.copyOf(elements, index + 1);
116             }
117
118             elements[index] = requireNonNull(obj);
119             size++;
120             return this;
121         }
122
123         @Override
124         public int size() {
125             return size;
126         }
127
128         @Override
129         StatementMap ensureCapacity(final int expectedLimit) {
130             if (elements.length < expectedLimit) {
131                 elements = Arrays.copyOf(elements, expectedLimit);
132             }
133             return this;
134         }
135
136         @Override
137         public Iterator<AbstractResumedStatement<?, ?, ?>> iterator() {
138             return new AbstractIterator<>() {
139                 private int nextOffset = 0;
140
141                 @Override
142                 protected AbstractResumedStatement<?, ?, ?> computeNext() {
143                     while (nextOffset < elements.length) {
144                         final AbstractResumedStatement<?, ?, ?> ret = elements[nextOffset++];
145                         if (ret != null) {
146                             return ret;
147                         }
148                     }
149
150                     return endOfData();
151                 }
152             };
153         }
154     }
155
156     private static final class Singleton extends StatementMap {
157         private final AbstractResumedStatement<?, ?, ?> object;
158
159         Singleton(final AbstractResumedStatement<?, ?, ?> object) {
160             this.object = requireNonNull(object);
161         }
162
163         @Override
164         AbstractResumedStatement<?, ?, ?> get(final int index) {
165             return index == 0 ? object : null;
166         }
167
168         @Override
169         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
170             checkArgument(index != 0);
171             return new Regular(this.object, index, obj);
172         }
173
174         @Override
175         public int size() {
176             return 1;
177         }
178
179         @Override
180         StatementMap ensureCapacity(final int expectedLimit) {
181             return expectedLimit < 2 ? this : new Regular(expectedLimit, 0, object);
182         }
183
184         @Override
185         public Iterator<AbstractResumedStatement<?, ?, ?>> iterator() {
186             return Iterators.singletonIterator(object);
187         }
188     }
189
190     private static final StatementMap EMPTY = new Empty();
191
192     static StatementMap empty() {
193         return EMPTY;
194     }
195
196     /**
197      * Return the statement context at specified index.
198      *
199      * @param index Element index, must be non-negative
200      * @return Requested element or null if there is no element at that index
201      */
202     abstract @Nullable AbstractResumedStatement<?, ?, ?> get(int index);
203
204     /**
205      * Add a statement at specified index.
206      *
207      * @param index Element index, must be non-negative
208      * @param obj Object to store
209      * @return New statement map
210      * @throws IllegalArgumentException if the index is already occupied
211      */
212     abstract @NonNull StatementMap put(int index, @NonNull AbstractResumedStatement<?, ?, ?> obj);
213
214     abstract @NonNull StatementMap ensureCapacity(int expectedLimit);
215 }