/*
* Copyright 2003-2011 JetBrains s.r.o.
*
* 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 jetbrains.mps.typesystem.inference.util;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import jetbrains.mps.lang.pattern.util.MatchingUtil;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class StructuralNodeMap<T> implements Map<SNode, T> {
private Map<SNode, SNode> myRepresentatorsMap = new THashMap<SNode, SNode>();
private Map<SNode, T> myMap = new THashMap<SNode, T>();
private Set<SNode> myAbsentNodes = new THashSet<SNode>();
public SNode getKeyRepresentator(SNode node) {
return myRepresentatorsMap.get(node);
}
@Override
public int size() {
return myMap.size();
}
@Override
public boolean isEmpty() {
return myMap.isEmpty();
}
@Override
public boolean containsValue(Object value) {
return myMap.containsValue(value);
}
@Override
public void putAll(Map<? extends SNode, ? extends T> t) {
throw new UnsupportedOperationException();
}
@Override
public Set<SNode> keySet() {
return myMap.keySet();
}
@Override
public void clear() {
myRepresentatorsMap.clear();
myMap.clear();
myAbsentNodes.clear();
}
@Override
public Collection<T> values() {
return myMap.values();
}
@Override
public Set<Entry<SNode, T>> entrySet() {
return myMap.entrySet();
}
@Override
public T get(Object key) {
if (!(key instanceof SNode)) return null;
SNode keyNode = (SNode) key;
SNode representator = getKeyRepresentator(keyNode);
if (representator == null) {
if (myAbsentNodes.contains(keyNode)) return null;
for (SNode node : myMap.keySet()) {
if (MatchingUtil.matchNodes(node, keyNode)) {
myRepresentatorsMap.put(keyNode, node);
return myMap.get(node);
}
}
}
if (representator == null) {
myAbsentNodes.add(keyNode);
return null;
}
return myMap.get(representator);
}
@Override
public T put(SNode keyNode, T value) {
SNode representator = getKeyRepresentator(keyNode);
if (representator == null) {
for (SNode node : myMap.keySet()) {
if (MatchingUtil.matchNodes(node, keyNode)) {
myRepresentatorsMap.put(keyNode, node);
return myMap.put(node, value);
}
}
}
if (representator == null) {
myRepresentatorsMap.put(keyNode, keyNode);
myAbsentNodes.remove(keyNode);
representator = keyNode;
}
return myMap.put(representator, value);
}
@Override
public T remove(Object key) {
if (!(key instanceof SNode)) return null;
SNode keyNode = (SNode) key;
myAbsentNodes.add(keyNode);
SNode representator = getKeyRepresentator(keyNode);
if (representator == null) {
for (SNode node : myMap.keySet()) {
if (MatchingUtil.matchNodes(node, keyNode)) {
myRepresentatorsMap.put(keyNode, node);
return myMap.remove(node);
}
}
}
if (representator == null) return null;
return myMap.remove(representator);
}
@Override
public boolean containsKey(Object key) {
if (!(key instanceof SNode)) return false;
SNode keyNode = (SNode) key;
SNode representator = getKeyRepresentator(keyNode);
if (representator == null) {
if (myAbsentNodes.contains(keyNode)) return false;
for (SNode node : myMap.keySet()) {
if (MatchingUtil.matchNodes(node, keyNode)) {
myRepresentatorsMap.put(keyNode, node);
return myMap.containsKey(node);
}
}
}
if (representator == null) {
myAbsentNodes.add(keyNode);
return false;
}
return myMap.containsKey(representator);
}
}