Use switch expressions for CopyType dispatch
[yangtools.git] / parser / 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<OriginalStmtCtx<?, ?, ?>> {
36     private static final class Empty extends StatementMap {
37         private static final Iterator<OriginalStmtCtx<?, ?, ?>> 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<OriginalStmtCtx<?, ?, ?>> 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 OriginalStmtCtx<?, ?, ?> 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 OriginalStmtCtx<?, ?, ?>> action) {
70             // No-op
71         }
72
73         @Override
74         public Iterator<OriginalStmtCtx<?, ?, ?>> iterator() {
75             return EMPTY_ITERATOR;
76         }
77     }
78
79     private static final class Regular extends StatementMap {
80         private OriginalStmtCtx<?, ?, ?>[] elements;
81         private int size;
82
83         Regular(final int expectedLimit) {
84             elements = new OriginalStmtCtx<?, ?, ?>[expectedLimit];
85         }
86
87         Regular(final int index, final OriginalStmtCtx<?, ?, ?> object) {
88             this(index + 1, index, object);
89         }
90
91         Regular(final OriginalStmtCtx<?, ?, ?> object0, final int index, final OriginalStmtCtx<?, ?, ?> object) {
92             this(index + 1, 0, object0);
93             elements[index] = requireNonNull(object);
94             size = 2;
95         }
96
97         Regular(final int expectedLimit, final int index, final OriginalStmtCtx<?, ?, ?> object) {
98             this(expectedLimit);
99             elements[index] = requireNonNull(object);
100             size = 1;
101         }
102
103         @Override
104         OriginalStmtCtx<?, ?, ?> get(final int index) {
105             return index >= elements.length ? null : elements[index];
106         }
107
108         @Override
109         StatementMap put(final int index, final OriginalStmtCtx<?, ?, ?> obj) {
110             if (index < elements.length) {
111                 checkArgument(elements[index] == null);
112             } else {
113                 // FIXME: detect linear growth
114                 elements = Arrays.copyOf(elements, index + 1);
115             }
116
117             elements[index] = requireNonNull(obj);
118             size++;
119             return this;
120         }
121
122         @Override
123         public int size() {
124             return size;
125         }
126
127         @Override
128         StatementMap ensureCapacity(final int expectedLimit) {
129             if (elements.length < expectedLimit) {
130                 elements = Arrays.copyOf(elements, expectedLimit);
131             }
132             return this;
133         }
134
135         @Override
136         public Iterator<OriginalStmtCtx<?, ?, ?>> iterator() {
137             return new Iter(this);
138         }
139
140         private static final class Iter extends AbstractIterator<OriginalStmtCtx<?, ?, ?>> {
141             private int nextOffset = 0;
142             private Regular map;
143
144             Iter(final Regular map) {
145                 this.map = requireNonNull(map);
146             }
147
148             @Override
149             protected OriginalStmtCtx<?, ?, ?> computeNext() {
150                 while (nextOffset < map.elements.length) {
151                     final OriginalStmtCtx<?, ?, ?> ret = map.elements[nextOffset++];
152                     if (ret != null) {
153                         return ret;
154                     }
155                 }
156
157                 map = null;
158                 return endOfData();
159             }
160         }
161     }
162
163     private static final class Singleton extends StatementMap {
164         private final OriginalStmtCtx<?, ?, ?> object;
165
166         Singleton(final OriginalStmtCtx<?, ?, ?> object) {
167             this.object = requireNonNull(object);
168         }
169
170         @Override
171         OriginalStmtCtx<?, ?, ?> get(final int index) {
172             return index == 0 ? object : null;
173         }
174
175         @Override
176         StatementMap put(final int index, final OriginalStmtCtx<?, ?, ?> obj) {
177             checkArgument(index != 0);
178             return new Regular(object, index, obj);
179         }
180
181         @Override
182         public int size() {
183             return 1;
184         }
185
186         @Override
187         StatementMap ensureCapacity(final int expectedLimit) {
188             return expectedLimit < 2 ? this : new Regular(expectedLimit, 0, object);
189         }
190
191         @Override
192         public Iterator<OriginalStmtCtx<?, ?, ?>> iterator() {
193             return Iterators.singletonIterator(object);
194         }
195     }
196
197     private static final @NonNull StatementMap EMPTY = new Empty();
198
199     /**
200      * Return an empty map.
201      *
202      * @return An empty map.
203      */
204     static @NonNull StatementMap empty() {
205         return EMPTY;
206     }
207
208     /**
209      * Return the statement context at specified index.
210      *
211      * @param index Element index, must be non-negative
212      * @return Requested element or null if there is no element at that index
213      */
214     abstract @Nullable OriginalStmtCtx<?, ?, ?> get(int index);
215
216     /**
217      * Add a statement at specified index.
218      *
219      * @param index Element index, must be non-negative
220      * @param obj Object to store
221      * @return New statement map
222      * @throws IllegalArgumentException if the index is already occupied
223      */
224     abstract @NonNull StatementMap put(int index, @NonNull OriginalStmtCtx<?, ?, ?> obj);
225
226     /**
227      * Ensure storage space for at least {@code explectedLimit} substatements.
228      *
229      * @param expectedLimit Expected number of substatements
230      * @return New statement map
231      */
232     abstract @NonNull StatementMap ensureCapacity(int expectedLimit);
233 }