Extract AbstractResumedStatement
[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 java.util.Objects.requireNonNull;
12
13 import com.google.common.base.MoreObjects;
14 import com.google.common.collect.AbstractIterator;
15 import com.google.common.collect.ImmutableList;
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  * @author Robert Varga
29  */
30 abstract class StatementMap {
31     private static final class Empty extends StatementMap {
32         @Override
33         AbstractResumedStatement<?, ?, ?> get(final int index) {
34             return null;
35         }
36
37         @Override
38         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
39             return index == 0 ? new Singleton(obj) : new Regular(index, obj);
40         }
41
42         @Override
43         Collection<AbstractResumedStatement<?, ?, ?>> values() {
44             return ImmutableList.of();
45         }
46
47         @Override
48         int size() {
49             return 0;
50         }
51
52         @Override
53         StatementMap ensureCapacity(final int expectedLimit) {
54             return expectedLimit < 2 ? this : new Regular(expectedLimit);
55         }
56
57         @Override
58         int capacity() {
59             return 0;
60         }
61     }
62
63     private static final class Regular extends StatementMap {
64         private AbstractResumedStatement<?, ?, ?>[] elements;
65         private int size;
66
67         Regular(final int expectedLimit) {
68             elements = new AbstractResumedStatement<?, ?, ?>[expectedLimit];
69         }
70
71         Regular(final int index, final AbstractResumedStatement<?, ?, ?> object) {
72             this(index + 1, index, object);
73         }
74
75         Regular(final AbstractResumedStatement<?, ?, ?> object0, final int index,
76                 final AbstractResumedStatement<?, ?, ?> object) {
77             this(index + 1, 0, object0);
78             elements[index] = requireNonNull(object);
79             size = 2;
80         }
81
82         Regular(final int expectedLimit, final int index, final AbstractResumedStatement<?, ?, ?> object) {
83             this(expectedLimit);
84             elements[index] = requireNonNull(object);
85             size = 1;
86         }
87
88         @Override
89         AbstractResumedStatement<?, ?, ?> get(final int index) {
90             return index >= elements.length ? null : elements[index];
91         }
92
93         @Override
94         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
95             if (index < elements.length) {
96                 checkArgument(elements[index] == null);
97             } else {
98                 // FIXME: detect linear growth
99                 elements = Arrays.copyOf(elements, index + 1);
100             }
101
102             elements[index] = requireNonNull(obj);
103             size++;
104             return this;
105         }
106
107         @Override
108         Collection<AbstractResumedStatement<?, ?, ?>> values() {
109             return new RegularAsCollection<>(elements, size);
110         }
111
112         @Override
113         int size() {
114             return size;
115         }
116
117         @Override
118         StatementMap ensureCapacity(final int expectedLimit) {
119             if (elements.length < expectedLimit) {
120                 elements = Arrays.copyOf(elements, expectedLimit);
121             }
122             return this;
123         }
124
125         @Override
126         int capacity() {
127             return elements.length;
128         }
129     }
130
131     private static final class RegularAsCollection<T> extends AbstractCollection<T> {
132         private final T[] elements;
133         private final int size;
134
135         RegularAsCollection(final T[] elements, final int size) {
136             this.elements = requireNonNull(elements);
137             this.size = size;
138         }
139
140         @Override
141         public void forEach(final Consumer<? super T> action) {
142             for (T e : elements) {
143                 if (e != null) {
144                     action.accept(e);
145                 }
146             }
147         }
148
149         @Override
150         public Iterator<T> iterator() {
151             return new AbstractIterator<>() {
152                 private int nextOffset = 0;
153
154                 @Override
155                 protected T computeNext() {
156                     while (nextOffset < elements.length) {
157                         final T ret = elements[nextOffset++];
158                         if (ret != null) {
159                             return ret;
160                         }
161                     }
162
163                     return endOfData();
164                 }
165             };
166         }
167
168         @Override
169         public int size() {
170             return size;
171         }
172     }
173
174     private static final class Singleton extends StatementMap {
175         private final AbstractResumedStatement<?, ?, ?> object;
176
177         Singleton(final AbstractResumedStatement<?, ?, ?> object) {
178             this.object = requireNonNull(object);
179         }
180
181         @Override
182         AbstractResumedStatement<?, ?, ?> get(final int index) {
183             return index == 0 ? object : null;
184         }
185
186         @Override
187         StatementMap put(final int index, final AbstractResumedStatement<?, ?, ?> obj) {
188             checkArgument(index != 0);
189             return new Regular(this.object, index, obj);
190         }
191
192         @Override
193         Collection<AbstractResumedStatement<?, ?, ?>> values() {
194             return ImmutableList.of(object);
195         }
196
197         @Override
198         int size() {
199             return 1;
200         }
201
202         @Override
203         StatementMap ensureCapacity(final int expectedLimit) {
204             return expectedLimit < 2 ? this : new Regular(expectedLimit, 0, object);
205         }
206
207         @Override
208         int capacity() {
209             return 1;
210         }
211     }
212
213     private static final StatementMap EMPTY = new Empty();
214
215     static StatementMap empty() {
216         return EMPTY;
217     }
218
219     /**
220      * Return the statement context at specified index.
221      *
222      * @param index Element index, must be non-negative
223      * @return Requested element or null if there is no element at that index
224      */
225     abstract @Nullable AbstractResumedStatement<?, ?, ?> get(int index);
226
227     /**
228      * Add a statement at specified index.
229      *
230      * @param index Element index, must be non-negative
231      * @param obj Object to store
232      * @return New statement map
233      * @throws IllegalArgumentException if the index is already occupied
234      */
235     abstract @NonNull StatementMap put(int index, @NonNull AbstractResumedStatement<?, ?, ?> obj);
236
237     /**
238      * Return a read-only view of the elements in this map. Unlike other maps, this view does not detect concurrent
239      * modification. Iteration is performed in order of increasing offset. In face of concurrent modification, number
240      * of elements returned through iteration may not match the size reported via {@link Collection#size()}.
241      *
242      * @return Read-only view of available statements.
243      */
244     abstract @NonNull Collection<AbstractResumedStatement<?, ?, ?>> values();
245
246     abstract int size();
247
248     abstract @NonNull StatementMap ensureCapacity(int expectedLimit);
249
250     abstract int capacity();
251
252     @Override
253     public final String toString() {
254         return MoreObjects.toStringHelper(StatementMap.class).add("values", values()).toString();
255     }
256 }