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