BUG-5222: Reuse substatements across phases
[yangtools.git] / yang / yang-parser-impl / 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 com.google.common.base.Preconditions;
11 import com.google.common.collect.AbstractIterator;
12 import com.google.common.collect.ImmutableList;
13 import java.util.AbstractCollection;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Iterator;
17 import java.util.function.Consumer;
18 import javax.annotation.Nonnull;
19 import javax.annotation.Nullable;
20
21 /**
22  * Simple integer-to-StatementContextBase map optimized for size and restricted in scope of operations. It does not
23  * implement {@link java.util.Map} for simplicity's sake.
24  *
25  * @author Robert Varga
26  */
27 abstract class StatementMap {
28     private static final class Empty extends StatementMap {
29         @Override
30         StatementContextBase<?, ?, ?> get(final int index) {
31             return null;
32         }
33
34         @Override
35         StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
36             return index == 0 ? new Singleton(object) : new Regular(index, object);
37         }
38
39         @Override
40         Collection<StatementContextBase<?, ?, ?>> values() {
41             return ImmutableList.of();
42         }
43     }
44
45     private static final class Regular extends StatementMap {
46         private StatementContextBase<?, ?, ?>[] elements;
47
48         Regular(final int index, final StatementContextBase<?, ?, ?> object) {
49             elements = new StatementContextBase<?, ?, ?>[index + 1];
50             elements[index] = Preconditions.checkNotNull(object);
51         }
52
53         Regular(final StatementContextBase<?, ?, ?> object0, final int index,
54                 final StatementContextBase<?, ?, ?> object) {
55             elements = new StatementContextBase<?, ?, ?>[index + 1];
56             elements[0] = Preconditions.checkNotNull(object0);
57             elements[index] = Preconditions.checkNotNull(object);
58         }
59
60         @Override
61         StatementContextBase<?, ?, ?> get(final int index) {
62             if (index >= elements.length) {
63                 return null;
64             }
65
66             return elements[index];
67         }
68
69         @Override
70         StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
71             if (index < elements.length) {
72                 Preconditions.checkArgument(elements[index] == null);
73             } else {
74                 elements = Arrays.copyOf(elements, index + 1);
75             }
76
77             elements[index] = Preconditions.checkNotNull(object);
78             return this;
79         }
80
81         @Override
82         Collection<StatementContextBase<?, ?, ?>> values() {
83             return new RegularAsCollection<>(elements);
84         }
85     }
86
87     private static final class RegularAsCollection<T> extends AbstractCollection<T> {
88         private final T[] elements;
89
90         RegularAsCollection(final T[] elements) {
91             this.elements = Preconditions.checkNotNull(elements);
92         }
93
94         @Override
95         public void forEach(final Consumer<? super T> action) {
96             for (T e : elements) {
97                 if (e != null) {
98                     action.accept(e);
99                 }
100             }
101         }
102
103         @Override
104         public boolean isEmpty() {
105             // This has a single-use and when it is instantiated, we know to have at least two items
106             return false;
107         }
108
109         @Override
110         public Iterator<T> iterator() {
111             return new AbstractIterator<T>() {
112                 private int nextOffset = 0;
113
114                 @Override
115                 protected T computeNext() {
116                     while (nextOffset < elements.length) {
117                         final T ret = elements[nextOffset++];
118                         if (ret != null) {
119                             return ret;
120                         }
121                     }
122
123                     return endOfData();
124                 }
125             };
126         }
127
128         @Override
129         public int size() {
130             // Optimized for non-sparse case
131             int nulls = 0;
132             for (T e : elements) {
133                 if (e == null) {
134                     nulls++;
135                 }
136             }
137
138             return elements.length - nulls;
139         }
140     }
141
142
143     private static final class Singleton extends StatementMap {
144         private final StatementContextBase<?, ?, ?> object;
145
146         Singleton(final StatementContextBase<?, ?, ?> object) {
147             this.object = Preconditions.checkNotNull(object);
148         }
149
150         @Override
151         StatementContextBase<?, ?, ?> get(final int index) {
152             return index == 0 ? object : null;
153         }
154
155         @Override
156         StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
157             Preconditions.checkArgument(index != 0);
158             return new Regular(this.object, index, object);
159         }
160
161         @Override
162         Collection<StatementContextBase<?, ?, ?>> values() {
163             return ImmutableList.of(object);
164         }
165     }
166
167     private static final StatementMap EMPTY = new Empty();
168
169     static StatementMap empty() {
170         return EMPTY;
171     }
172
173     /**
174      * Return the statement context at specified index.
175      *
176      * @param index Element index, must be non-negative
177      * @return Requested element or null if there is no element at that index
178      */
179     abstract @Nullable StatementContextBase<?, ?, ?> get(int index);
180
181     /**
182      * Add a statement at specified index.
183      *
184      * @param index Element index, must be non-negative
185      * @param object Object to store
186      * @return New statement map
187      * @throws IllegalArgumentException if the index is already occupied
188      */
189     abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase<?, ?, ?> object);
190
191     /**
192      * Return a read-only view of the elements in this map. Unlike other maps, this view does not detect concurrent
193      * modification. Iteration is performed in order of increasing offset. In face of concurrent modification, number
194      * of elements returned through iteration may not match the size reported via {@link Collection#size()}.
195      *
196      * @return Read-only view of available statements.
197      */
198     abstract @Nonnull Collection<StatementContextBase<?, ?, ?>> values();
199 }