3f33c988a6e1827f99a62973e55bb55a748a61b5
[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             if (index >= elements.length) {
90                 return null;
91             }
92
93             return elements[index];
94         }
95
96         @Override
97         StatementMap put(final int index, final StatementContextBase<?, ?, ?> obj) {
98             if (index < elements.length) {
99                 checkArgument(elements[index] == null);
100             } else {
101                 // FIXME: detect linear growth
102                 elements = Arrays.copyOf(elements, index + 1);
103             }
104
105             elements[index] = requireNonNull(obj);
106             size++;
107             return this;
108         }
109
110         @Override
111         Collection<StatementContextBase<?, ?, ?>> values() {
112             return new RegularAsCollection<>(elements, size);
113         }
114
115         @Override
116         int size() {
117             return size;
118         }
119
120         @Override
121         StatementMap ensureCapacity(final int expectedLimit) {
122             if (elements.length < expectedLimit) {
123                 elements = Arrays.copyOf(elements, expectedLimit);
124             }
125             return this;
126         }
127
128         @Override
129         int capacity() {
130             return elements.length;
131         }
132     }
133
134     private static final class RegularAsCollection<T> extends AbstractCollection<T> {
135         private final T[] elements;
136         private final int size;
137
138         RegularAsCollection(final T[] elements, final int size) {
139             this.elements = requireNonNull(elements);
140             this.size = size;
141         }
142
143         @Override
144         public void forEach(final Consumer<? super T> action) {
145             for (T e : elements) {
146                 if (e != null) {
147                     action.accept(e);
148                 }
149             }
150         }
151
152         @Override
153         public Iterator<T> iterator() {
154             return new AbstractIterator<T>() {
155                 private int nextOffset = 0;
156
157                 @Override
158                 protected T computeNext() {
159                     while (nextOffset < elements.length) {
160                         final T ret = elements[nextOffset++];
161                         if (ret != null) {
162                             return ret;
163                         }
164                     }
165
166                     return endOfData();
167                 }
168             };
169         }
170
171         @Override
172         public int size() {
173             return size;
174         }
175     }
176
177     private static final class Singleton extends StatementMap {
178         private final StatementContextBase<?, ?, ?> object;
179
180         Singleton(final StatementContextBase<?, ?, ?> object) {
181             this.object = requireNonNull(object);
182         }
183
184         @Override
185         StatementContextBase<?, ?, ?> get(final int index) {
186             return index == 0 ? object : null;
187         }
188
189         @Override
190         StatementMap put(final int index, final StatementContextBase<?, ?, ?> obj) {
191             checkArgument(index != 0);
192             return new Regular(this.object, index, obj);
193         }
194
195         @Override
196         Collection<StatementContextBase<?, ?, ?>> values() {
197             return ImmutableList.of(object);
198         }
199
200         @Override
201         int size() {
202             return 1;
203         }
204
205         @Override
206         StatementMap ensureCapacity(final int expectedLimit) {
207             return expectedLimit < 2 ? this : new Regular(expectedLimit, 0, object);
208         }
209
210         @Override
211         int capacity() {
212             return 1;
213         }
214     }
215
216     private static final StatementMap EMPTY = new Empty();
217
218     static StatementMap empty() {
219         return EMPTY;
220     }
221
222     /**
223      * Return the statement context at specified index.
224      *
225      * @param index Element index, must be non-negative
226      * @return Requested element or null if there is no element at that index
227      */
228     abstract @Nullable StatementContextBase<?, ?, ?> get(int index);
229
230     /**
231      * Add a statement at specified index.
232      *
233      * @param index Element index, must be non-negative
234      * @param obj Object to store
235      * @return New statement map
236      * @throws IllegalArgumentException if the index is already occupied
237      */
238     abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase<?, ?, ?> obj);
239
240     /**
241      * Return a read-only view of the elements in this map. Unlike other maps, this view does not detect concurrent
242      * modification. Iteration is performed in order of increasing offset. In face of concurrent modification, number
243      * of elements returned through iteration may not match the size reported via {@link Collection#size()}.
244      *
245      * @return Read-only view of available statements.
246      */
247     abstract @Nonnull Collection<StatementContextBase<?, ?, ?>> values();
248
249     abstract int size();
250
251     abstract StatementMap ensureCapacity(int expectedLimit);
252
253     abstract int capacity();
254 }