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