/* * Copyright 2003-2013 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.idea.core.psi.impl.events; import jetbrains.mps.smodel.ModelAccess; import jetbrains.mps.util.Computable; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeId; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; /** * User: fyodor * Date: 2/18/13 */ public final class NodePath { private List<SNodeId> myPath; public static final NodePath EMPTY = new NodePath(Collections.<SNodeId>emptyList()); public static NodePath forSNode (final SNode sNode) { List<SNodeId> path = ModelAccess.instance().runReadAction(new Computable<List<SNodeId>>() { @Override public List<SNodeId> compute() { LinkedList<SNodeId> path = new LinkedList<SNodeId>(); for (SNode sn = sNode; sn != null; sn = sn.getParent()) { SNodeId nodeId = sn.getNodeId(); if (nodeId == null) return null; path.addFirst(nodeId); } return path; } }); if (path == null) { throw new IllegalArgumentException("null SNodeId"); } return new NodePath (path); } public NodePath (Collection<SNodeId> ids) { myPath = new ArrayList<SNodeId>(ids); } boolean isEmpty () { return myPath.isEmpty(); } public SNodeId root() { if (myPath.isEmpty()) throw new IllegalStateException("empty NodePath"); return myPath.get(0); } public Iterable<SNodeId> path () { return myPath; } public SNodeId leaf() { if (myPath.isEmpty()) throw new IllegalStateException("empty NodePath"); return myPath.get(myPath.size()-1); } public NodePath findLowestCommonParent (NodePath that) { if (isEmpty()) return this; if (that.isEmpty()) return that; ListIterator<SNodeId> thisIt = this.myPath.listIterator(); ListIterator<SNodeId> thatIt = that.myPath.listIterator(); LinkedList<SNodeId> result = null; while (thisIt.hasNext() && thatIt.hasNext()) { SNodeId thisId = thisIt.next(); SNodeId thatId = thatIt.next(); if (!thisId.equals(thatId)) { break; } if (result == null) { result = new LinkedList<SNodeId>(); } result.addLast(thisId); } return result != null ? new NodePath(result) : null; } @Override public boolean equals(Object that) { if (that == null) return false; if (that.getClass() != NodePath.class) return false; return this.myPath == ((NodePath)that).myPath || (this.myPath != null && this.myPath.equals(((NodePath)that).myPath)); } @Override public int hashCode() { return myPath != null ? myPath.hashCode() * 37 : 137; } }