| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 package com.google.dart.compiler.resolver; |
| 6 |
| 7 import com.google.dart.compiler.ast.DartLabel; |
| 8 import com.google.dart.compiler.ast.DartNode; |
| 9 import com.google.dart.compiler.ast.Modifiers; |
| 10 import com.google.dart.compiler.type.Type; |
| 11 |
| 12 import java.util.ArrayList; |
| 13 import java.util.List; |
| 14 |
| 15 /** |
| 16 * A more efficient version of {@link com.google.common.collect.Multimap} specif
ically for |
| 17 * {@link Element} |
| 18 */ |
| 19 class ElementMap { |
| 20 |
| 21 /** |
| 22 * A synthetic place holder for an element where the name given to the element
map does not match |
| 23 * the value returned by {@link Element#getName()} or where there are multiple
elements associated |
| 24 * with the same name. |
| 25 */ |
| 26 static class ElementHolder implements Element { |
| 27 private static final String INTERNAL_ONLY_ERROR = "ElementHolder should not
be accessed outside this class"; |
| 28 |
| 29 final String name; |
| 30 final Element element; |
| 31 ElementHolder nextHolder; |
| 32 |
| 33 ElementHolder(String name, Element element) { |
| 34 this.name = name; |
| 35 this.element = element; |
| 36 } |
| 37 |
| 38 @Override |
| 39 public EnclosingElement getEnclosingElement() { |
| 40 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 41 } |
| 42 |
| 43 @Override |
| 44 public ElementKind getKind() { |
| 45 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 46 } |
| 47 |
| 48 @Override |
| 49 public Modifiers getModifiers() { |
| 50 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 51 } |
| 52 |
| 53 @Override |
| 54 public String getName() { |
| 55 return name; |
| 56 } |
| 57 |
| 58 @Override |
| 59 public DartNode getNode() { |
| 60 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 61 } |
| 62 |
| 63 @Override |
| 64 public String getOriginalSymbolName() { |
| 65 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 66 } |
| 67 |
| 68 @Override |
| 69 public Type getType() { |
| 70 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 71 } |
| 72 |
| 73 @Override |
| 74 public boolean isDynamic() { |
| 75 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 76 } |
| 77 |
| 78 @Override |
| 79 public void setNode(DartLabel node) { |
| 80 throw new AssertionError(INTERNAL_ONLY_ERROR); |
| 81 } |
| 82 } |
| 83 |
| 84 // Array indexed by hashed name ... length is always power of 2 |
| 85 private Element[] elements; |
| 86 private List<Element> ordered = new ArrayList<Element>(); |
| 87 |
| 88 ElementMap() { |
| 89 clear(); |
| 90 } |
| 91 |
| 92 /** |
| 93 * Associate the specified element with the specified name. If the element is
already associated |
| 94 * with that name, do not associate it again. |
| 95 */ |
| 96 void add(String name, Element element) { |
| 97 |
| 98 // Most of the time name equals getName() thus holder == element |
| 99 Element newHolder; |
| 100 if (name.equals(element.getName())) { |
| 101 newHolder = element; |
| 102 } else { |
| 103 newHolder = new ElementHolder(name, element); |
| 104 } |
| 105 |
| 106 // 75% fill rate which anecdotal evidence claims is a good threshold for gro
wing |
| 107 if ((elements.length >> 2) * 3 <= size()) { |
| 108 grow(); |
| 109 } |
| 110 int index = internalAdd(newHolder); |
| 111 if (index == -1) { |
| 112 ordered.add(element); |
| 113 return; |
| 114 } |
| 115 |
| 116 // Handle existing element with the same name |
| 117 Element existingHolder = elements[index]; |
| 118 if (existingHolder == element) { |
| 119 return; |
| 120 } |
| 121 if (!(existingHolder instanceof ElementHolder)) { |
| 122 existingHolder = new ElementHolder(name, existingHolder); |
| 123 elements[index] = existingHolder; |
| 124 } |
| 125 |
| 126 // Check the list for a duplicate element entry, and append if none found |
| 127 ElementHolder holder = (ElementHolder) existingHolder; |
| 128 while (true) { |
| 129 if (holder.element == element) { |
| 130 return; |
| 131 } |
| 132 if (holder.nextHolder == null) { |
| 133 holder.nextHolder = new ElementHolder(name, element); |
| 134 ordered.add(element); |
| 135 return; |
| 136 } |
| 137 holder = holder.nextHolder; |
| 138 } |
| 139 } |
| 140 |
| 141 void clear() { |
| 142 elements = new Element[16]; |
| 143 ordered.clear(); |
| 144 } |
| 145 |
| 146 /** |
| 147 * Answer the element last associated with the specified name. |
| 148 * |
| 149 * @return the element or <code>null</code> if none |
| 150 */ |
| 151 Element get(String name) { |
| 152 Element element = internalGet(name); |
| 153 if (element instanceof ElementHolder) { |
| 154 return ((ElementHolder) element).element; |
| 155 } else { |
| 156 return element; |
| 157 } |
| 158 } |
| 159 |
| 160 /** |
| 161 * Answer the element associated with the specified name and kind |
| 162 * |
| 163 * @return the element of that kind or <code>null</code> if none |
| 164 */ |
| 165 Element get(String name, ElementKind kind) { |
| 166 Element element = internalGet(name); |
| 167 if (element instanceof ElementHolder) { |
| 168 ElementHolder holder = (ElementHolder) element; |
| 169 while (true) { |
| 170 element = holder.element; |
| 171 if (ElementKind.of(element).equals(kind)) { |
| 172 return element; |
| 173 } |
| 174 holder = holder.nextHolder; |
| 175 if (holder == null) { |
| 176 break; |
| 177 } |
| 178 } |
| 179 } else { |
| 180 if (ElementKind.of(element).equals(kind)) { |
| 181 return element; |
| 182 } |
| 183 } |
| 184 return null; |
| 185 } |
| 186 |
| 187 boolean isEmpty() { |
| 188 return ordered.isEmpty(); |
| 189 } |
| 190 |
| 191 int size() { |
| 192 return ordered.size(); |
| 193 } |
| 194 |
| 195 List<Element> values() { |
| 196 return ordered; |
| 197 } |
| 198 |
| 199 private void grow() { |
| 200 Element[] old = elements; |
| 201 elements = new Element[elements.length << 2]; |
| 202 for (Element element : old) { |
| 203 if (element != null) { |
| 204 if (internalAdd(element) != -1) { |
| 205 // Every element in the array should have a unique name, so there shou
ld not be any collision |
| 206 throw new RuntimeException("Failed to grow: " + element.getName()); |
| 207 } |
| 208 } |
| 209 } |
| 210 } |
| 211 |
| 212 /** |
| 213 * If an element with the given name does not exist in the array, then add the
element and return |
| 214 * -1 otherwise nothing is added and the index of the existing element returne
d. |
| 215 */ |
| 216 private int internalAdd(Element element) { |
| 217 String name = element.getName(); |
| 218 int mask = elements.length - 1; |
| 219 int probe = name.hashCode() & mask; |
| 220 for (int i = probe; i < probe + mask + 1; i++) { |
| 221 int index = i & mask; |
| 222 Element current = elements[index]; |
| 223 if (current == null) { |
| 224 elements[index] = element; |
| 225 return -1; |
| 226 } |
| 227 if (current.getName().equals(name)) { |
| 228 return index; |
| 229 } |
| 230 } |
| 231 throw new AssertionError("overfilled array"); |
| 232 } |
| 233 |
| 234 private Element internalGet(String name) { |
| 235 Element element; |
| 236 int mask = elements.length - 1; |
| 237 int probe = name.hashCode() & mask; |
| 238 for (int i = probe; i < probe + mask + 1; i++) { |
| 239 element = elements[i & mask]; |
| 240 if (element == null || element.getName().equals(name)) { |
| 241 return element; |
| 242 } |
| 243 } |
| 244 throw new AssertionError("overfilled array"); |
| 245 } |
| 246 } |
| OLD | NEW |