org.gradle.model.internal.registry.RuleBindings Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.model.internal.registry;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.gradle.model.internal.core.ModelNode;
import org.gradle.model.internal.core.ModelPath;
import org.gradle.model.internal.type.ModelType;
import java.util.*;
class RuleBindings {
private final NodeAtStateIndex rulesBySubject;
private final NodeAtStateIndex rulesByInput;
private final PathPredicateIndex untypedPathReferences = new PathPredicateIndex();
private final PathPredicateIndex typedPathReferences = new PathPredicateIndex();
private final TypePredicateIndex scopeReferences = new TypePredicateIndex();
public RuleBindings() {
rulesBySubject = new NodeAtStateIndex("rulesBySubject");
rulesByInput = new NodeAtStateIndex("rulesByInput");
}
public void nodeCreated(ModelNodeInternal node) {
untypedPathReferences.addNode(node);
}
public void nodeDiscovered(ModelNodeInternal node) {
typedPathReferences.addNode(node);
scopeReferences.addNodeToScope(node.getPath(), node);
scopeReferences.addNodeToScope(node.getPath().getParent(), node);
}
private void bound(Reference reference, ModelNodeInternal node) {
ModelBinding binding = reference.binding;
binding.onBind(node);
reference.index.put(new NodeAtState(node.getPath(), binding.predicate.getState()), reference.owner);
}
public void remove(ModelNodeInternal node) {
untypedPathReferences.removeNode(node);
typedPathReferences.removeNode(node);
scopeReferences.removeNodeFromScope(node.getPath(), node);
scopeReferences.removeNodeFromScope(node.getPath().getParent(), node);
rulesBySubject.nodeRemoved(node);
rulesByInput.nodeRemoved(node);
}
public void add(RuleBinder ruleBinder) {
addRule(ruleBinder, rulesBySubject, ruleBinder.getSubjectBinding());
for (ModelBinding binding : ruleBinder.getInputBindings()) {
addRule(ruleBinder, rulesByInput, binding);
}
}
private void addRule(RuleBinder rule, NodeAtStateIndex index, ModelBinding binding) {
Reference reference = new Reference(rule, index, binding);
BindingPredicate predicate = binding.getPredicate();
if (predicate.getPath() != null) {
if (predicate.getScope() != null) {
throw new UnsupportedOperationException("Currently not implemented");
}
if (reference.binding.canBindInState(ModelNode.State.Registered)) {
untypedPathReferences.addReference(reference);
} else {
typedPathReferences.addReference(reference);
}
} else if (predicate.getScope() != null) {
scopeReferences.addReference(reference);
} else {
throw new UnsupportedOperationException("Currently not implemented");
}
}
private static void unbind(RuleBinder rule, ModelNodeInternal node) {
rule.getSubjectBinding().onUnbind(node);
for (ModelBinding binding : rule.getInputBindings()) {
binding.onUnbind(node);
}
}
/**
* Returns the set of rules with the given target as their subject.
*/
public Collection getRulesWithSubject(NodeAtState target) {
return rulesBySubject.get(target);
}
/**
* Returns the set of rules with the given input.
*/
public Collection getRulesWithInput(NodeAtState input) {
return rulesByInput.get(input);
}
private static class Reference {
final ModelBinding binding;
final NodeAtStateIndex index;
final RuleBinder owner;
public Reference(RuleBinder owner, NodeAtStateIndex index, ModelBinding binding) {
this.owner = owner;
this.index = index;
this.binding = binding;
}
@Override
public String toString() {
return binding + " in " + index.name;
}
}
private class PredicateMatches {
final List references = new ArrayList();
ModelNodeInternal match;
void match(ModelNodeInternal node) {
for (Reference reference : references) {
bound(reference, node);
}
match = node;
}
void add(Reference reference) {
references.add(reference);
if (match != null) {
bound(reference, match);
}
}
public void remove(ModelNodeInternal node) {
match = null;
}
}
private class PathPredicateIndex {
final Map predicates = Maps.newLinkedHashMap();
public void addNode(ModelNodeInternal node) {
predicatesForPath(node.getPath()).match(node);
}
public void addReference(Reference reference) {
ModelPath path = reference.binding.getPredicate().getPath();
predicatesForPath(path).add(reference);
}
private PredicateMatches predicatesForPath(ModelPath path) {
PredicateMatches predicatesForReference = predicates.get(path);
if (predicatesForReference == null) {
predicatesForReference = new PredicateMatches();
predicates.put(path, predicatesForReference);
}
return predicatesForReference;
}
public void removeNode(ModelNodeInternal node) {
predicatesForPath(node.getPath()).remove(node);
}
}
private class ScopeIndex {
final Map, PredicateMatches> types = Maps.newLinkedHashMap();
final List nodes = Lists.newArrayList();
public void addNode(ModelNodeInternal node) {
nodes.add(node);
for (Map.Entry, PredicateMatches> entry : types.entrySet()) {
if (node.canBeViewedAs(entry.getKey())) {
entry.getValue().match(node);
}
}
}
public void removeNode(ModelNodeInternal node) {
nodes.remove(node);
for (PredicateMatches matches : types.values()) {
if (matches.match == node) {
matches.remove(node);
}
}
}
public void addReference(Reference reference) {
ModelType> type = reference.binding.getPredicate().getType();
PredicateMatches predicateMatches = types.get(type);
boolean newType = predicateMatches == null;
if (predicateMatches == null) {
predicateMatches = new PredicateMatches();
types.put(type, predicateMatches);
}
predicateMatches.add(reference);
if (newType) {
for (ModelNodeInternal node : nodes) {
if (node.canBeViewedAs(type)) {
predicateMatches.match(node);
}
}
}
}
}
private class TypePredicateIndex {
final Map scopes = Maps.newLinkedHashMap();
public void addNodeToScope(ModelPath path, ModelNodeInternal node) {
scopeForPath(path).addNode(node);
}
public void removeNodeFromScope(ModelPath path, ModelNodeInternal node) {
scopeForPath(path).removeNode(node);
}
public void addReference(Reference reference) {
ModelPath path = reference.binding.getPredicate().getScope();
scopeForPath(path).addReference(reference);
}
private ScopeIndex scopeForPath(ModelPath path) {
ScopeIndex scope = scopes.get(path);
if (scope == null) {
scope = new ScopeIndex();
scopes.put(path, scope);
}
return scope;
}
}
private static class NodeAtStateIndex {
private final EnumMap>> boundAtState = Maps.newEnumMap(ModelNode.State.class);
private final String name;
private NodeAtStateIndex(String name) {
this.name = name;
}
private Map> getByState(ModelNode.State state) {
Map> map = boundAtState.get(state);
if (map == null) {
map = new HashMap>(64);
boundAtState.put(state, map);
}
return map;
}
public void nodeRemoved(ModelNodeInternal node) {
// This could be more efficient; assume that removal happens much less often than addition
for (ModelNode.State state : ModelNode.State.values()) {
Map> byState = getByState(state);
List remove = byState.remove(node.getPath().toString());
if (remove != null) {
for (RuleBinder rule : remove) {
unbind(rule, node);
}
}
}
}
public void put(NodeAtState nodeAtState, RuleBinder binder) {
Map> byState = getByState(nodeAtState.state);
String path = nodeAtState.path.toString();
List byPath = getByPath(byState, path);
if (!byPath.contains(binder)) {
byPath.add(binder);
}
}
private List getByPath(Map> byState, String path) {
List ruleBinders = byState.get(path);
if (ruleBinders == null) {
ruleBinders = new LinkedList();
byState.put(path, ruleBinders);
}
return ruleBinders;
}
/**
* Returns rules for given target at state.
*/
public Collection get(NodeAtState nodeAtState) {
return getByPath(getByState(nodeAtState.state), nodeAtState.path.toString());
}
public void remove(ModelNodeInternal node, RuleBinder ruleBinder) {
unbind(ruleBinder, node);
for (ModelNode.State state : ModelNode.State.values()) {
Map> byState = getByState(state);
getByPath(byState, node.getPath().toString()).clear();
}
}
@Override
public String toString() {
return name;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy