blob: f4a416d5d00a27a2b5215d08899b055f124d922c [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of universe;
class SelectorMap<T> extends PartialTypeTree {
SelectorMap(Compiler compiler) : super(compiler);
SelectorMapNode<T> newSpecializedNode(ClassElement type)
=> new SelectorMapNode<T>(type);
T operator [](Selector selector) {
SelectorMapNode<T> node = findNode(selectorType(selector), false);
if (node == null) return null;
Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
if (selectors == null) return null;
for (Link link = selectors; !link.isEmpty; link = link.tail) {
SelectorValue<T> existing = link.head;
if (existing.selector.equalsUntyped(selector)) return existing.value;
}
return null;
}
void operator []=(Selector selector, T value) {
SelectorMapNode<T> node = findNode(selectorType(selector), true);
Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
if (selectors == null) {
// No existing selectors with the given name. Create a new
// linked list.
SelectorValue<T> head = new SelectorValue<T>(selector, value);
node.selectorsByName[selector.name] =
new Link<SelectorValue<T>>().prepend(head);
} else {
// Run through the linked list of selectors with the same name. If
// we find one that matches, we update the value in the mapping.
for (Link link = selectors; !link.isEmpty; link = link.tail) {
SelectorValue<T> existing = link.head;
// It is safe to ignore the type here, because all selector
// mappings that are stored in a single node have the same type.
if (existing.selector.equalsUntyped(selector)) {
existing.value = value;
return;
}
}
// We could not find an existing mapping for the selector, so
// we add a new one to the existing linked list.
SelectorValue<T> head = new SelectorValue<T>(selector, value);
node.selectorsByName[selector.name] = selectors.prepend(head);
}
}
// TODO(kasperl): Share code with the [] operator?
bool containsKey(Selector selector) {
SelectorMapNode<T> node = findNode(selectorType(selector), false);
if (node == null) return false;
Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
if (selectors == null) return false;
for (Link link = selectors; !link.isEmpty; link = link.tail) {
SelectorValue<T> existing = link.head;
if (existing.selector.equalsUntyped(selector)) return true;
}
return false;
}
/**
* Visits all mappings for selectors that may be used to invoke the
* given [member] element. If the [visit] function ever returns false,
* we abort the traversal early.
*/
void visitMatching(Element member, bool visit(Selector selector, T value)) {
assert(member.isMember());
if (root == null) return;
// TODO(kasperl): For now, we use a different implementation for
// visiting if the tree contains interface subtypes.
if (containsInterfaceSubtypes) {
visitAllMatching(member, visit);
} else {
visitHierarchyMatching(member, visit);
}
}
void visitAllMatching(Element member, bool visit(selector, value)) {
root.visitRecursively((SelectorMapNode<T> node) {
Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
if (selectors == null) return true;
for (Link link = selectors; !link.isEmpty; link = link.tail) {
SelectorValue<T> existing = link.head;
Selector selector = existing.selector;
// Since we're running through the entire tree we have to use
// the applies method that takes types into account.
if (selector.applies(member, compiler)) {
if (!visit(selector, existing.value)) return false;
}
}
return true;
});
}
void visitHierarchyMatching(Element member, bool visit(selector, value)) {
visitHierarchy(member.getEnclosingClass(), (SelectorMapNode<T> node) {
Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
if (selectors == null) return true;
for (Link link = selectors; !link.isEmpty; link = link.tail) {
SelectorValue<T> existing = link.head;
Selector selector = existing.selector;
if (selector.appliesUntyped(member, compiler)) {
if (!visit(selector, existing.value)) return false;
}
}
return true;
});
}
}
class SelectorMapNode<T> extends PartialTypeTreeNode {
final Map<SourceString, Link<SelectorValue<T>>> selectorsByName;
SelectorMapNode(ClassElement type) : super(type),
selectorsByName = new Map<SourceString, Link<SelectorValue<T>>>();
}
class SelectorValue<T> {
final Selector selector;
T value;
SelectorValue(this.selector, this.value);
toString() => "$selector -> $value";
}