7c632a99492fff8ce3ad268546bf1af149cb6692
[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         @Override
45         int size() {
46             return 0;
47         }
48     }
49
50     private static final class Regular extends StatementMap {
51         private StatementContextBase<?, ?, ?>[] elements;
52
53         Regular(final int index, final StatementContextBase<?, ?, ?> object) {
54             elements = new StatementContextBase<?, ?, ?>[index + 1];
55             elements[index] = Preconditions.checkNotNull(object);
56         }
57
58         Regular(final StatementContextBase<?, ?, ?> object0, final int index,
59                 final StatementContextBase<?, ?, ?> object) {
60             elements = new StatementContextBase<?, ?, ?>[index + 1];
61             elements[0] = Preconditions.checkNotNull(object0);
62             elements[index] = Preconditions.checkNotNull(object);
63         }
64
65         @Override
66         StatementContextBase<?, ?, ?> get(final int index) {
67             if (index >= elements.length) {
68                 return null;
69             }
70
71             return elements[index];
72         }
73
74         @Override
75         StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
76             if (index < elements.length) {
77                 Preconditions.checkArgument(elements[index] == null);
78             } else {
79                 elements = Arrays.copyOf(elements, index + 1);
80             }
81
82             elements[index] = Preconditions.checkNotNull(object);
83             return this;
84         }
85
86         @Override
87         Collection<StatementContextBase<?, ?, ?>> values() {
88             return new RegularAsCollection<>(elements);
89         }
90
91         @Override
92         int size() {
93             return countElements(elements);
94         }
95     }
96
97     static int countElements(final Object[] elements) {
98         // Optimized for non-sparse case
99         int nulls = 0;
100         for (Object e : elements) {
101             if (e == null) {
102                 nulls++;
103             }
104         }
105
106         return elements.length - nulls;
107     }
108
109     private static final class RegularAsCollection<T> extends AbstractCollection<T> {
110         private final T[] elements;
111
112         RegularAsCollection(final T[] elements) {
113             this.elements = Preconditions.checkNotNull(elements);
114         }
115
116         @Override
117         public void forEach(final Consumer<? super T> action) {
118             for (T e : elements) {
119                 if (e != null) {
120                     action.accept(e);
121                 }
122             }
123         }
124
125         @Override
126         public boolean isEmpty() {
127             // This has a single-use and when it is instantiated, we know to have at least two items
128             return false;
129         }
130
131         @Override
132         public Iterator<T> iterator() {
133             return new AbstractIterator<T>() {
134                 private int nextOffset = 0;
135
136                 @Override
137                 protected T computeNext() {
138                     while (nextOffset < elements.length) {
139                         final T ret = elements[nextOffset++];
140                         if (ret != null) {
141                             return ret;
142                         }
143                     }
144
145                     return endOfData();
146                 }
147             };
148         }
149
150         @Override
151         public int size() {
152             return countElements(elements);
153         }
154     }
155
156     private static final class Singleton extends StatementMap {
157         private final StatementContextBase<?, ?, ?> object;
158
159         Singleton(final StatementContextBase<?, ?, ?> object) {
160             this.object = Preconditions.checkNotNull(object);
161         }
162
163         @Override
164         StatementContextBase<?, ?, ?> get(final int index) {
165             return index == 0 ? object : null;
166         }
167
168         @Override
169         StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
170             Preconditions.checkArgument(index != 0);
171             return new Regular(this.object, index, object);
172         }
173
174         @Override
175         Collection<StatementContextBase<?, ?, ?>> values() {
176             return ImmutableList.of(object);
177         }
178
179         @Override
180         int size() {
181             return 1;
182         }
183     }
184
185     private static final StatementMap EMPTY = new Empty();
186
187     static StatementMap empty() {
188         return EMPTY;
189     }
190
191     /**
192      * Return the statement context at specified index.
193      *
194      * @param index Element index, must be non-negative
195      * @return Requested element or null if there is no element at that index
196      */
197     abstract @Nullable StatementContextBase<?, ?, ?> get(int index);
198
199     /**
200      * Add a statement at specified index.
201      *
202      * @param index Element index, must be non-negative
203      * @param object Object to store
204      * @return New statement map
205      * @throws IllegalArgumentException if the index is already occupied
206      */
207     abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase<?, ?, ?> object);
208
209     /**
210      * Return a read-only view of the elements in this map. Unlike other maps, this view does not detect concurrent
211      * modification. Iteration is performed in order of increasing offset. In face of concurrent modification, number
212      * of elements returned through iteration may not match the size reported via {@link Collection#size()}.
213      *
214      * @return Read-only view of available statements.
215      */
216     abstract @Nonnull Collection<StatementContextBase<?, ?, ?>> values();
217
218     abstract int size();
219 }