// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyil.util.type;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
/**
* This relation tracks the partial order among lifetimes.
*/
public class LifetimeRelation {
/**
* These are all lifetime parameters to the current method. There is no
* order between lifetimes in this set.
*/
private final Set<String> parameters;
/**
* These are lifetimes declared by named blocks. These lifetimes are totally
* ordered according to their position in the stack. Each lifetime in
* {@link #parameters} outlives all block lifetimes.
*/
private final Stack<String> blocks;
/**
* Create a new and empty lifetime relation.
*/
public LifetimeRelation() {
this.parameters = new HashSet<String>();
this.blocks = new Stack<String>();
}
/**
* Create an independent copy of the given lifetime relation.
*
* @param lifetimeRelation
*/
public LifetimeRelation(LifetimeRelation lifetimeRelation) {
this.parameters = new HashSet<String>(lifetimeRelation.parameters);
this.blocks = new Stack<String>();
this.blocks.addAll(lifetimeRelation.blocks);
}
/**
* Check whether the first (outer) lifetime outlives the second (inner)
* lifetime.
*
* @param outerLifetime
* @param innerLifetime
* @return
*/
public boolean outlives(String outerLifetime, String innerLifetime) {
if (outerLifetime.equals("*")) {
// * outlives everything
return true;
}
if (outerLifetime.equals(innerLifetime)) {
return true;
}
// Check whether the inner lifetime is from a named block.
int innerIndex = this.blocks.indexOf(innerLifetime);
if (innerIndex != -1) {
// All parameters are ordered before blocks.
if (this.parameters.contains(outerLifetime)) {
return true;
}
// Maybe another block at lower stack position?
int outerIndex = this.blocks.indexOf(outerLifetime);
if (outerIndex != -1 && outerIndex < innerIndex) {
return true;
}
}
return false;
}
/**
* Add a method's lifetime parameters to this relation.
*
* @param lifetimeParameters
*/
public void addParameters(Collection<String> lifetimeParameters) {
this.parameters.addAll(lifetimeParameters);
}
/**
* Enter a named block to this relation.
*
* @param lifetime
*/
public void startNamedBlock(String lifetime) {
this.blocks.push(lifetime);
}
/**
* Remove the named block with the given name from this relation. It also
* removes inner blocks in case that the given block is not the latest one.
*
* @param lifetime
*/
public void endNamedBlock(String lifetime) {
int i = this.blocks.lastIndexOf(lifetime);
if (i != -1) {
this.blocks.subList(i, this.blocks.size()).clear();
}
}
/**
* Replace this lifetime relation with the merge result of the given two
* relations.
*
* @param first
* @param second
*/
public void replaceWithMerge(LifetimeRelation first, LifetimeRelation second) {
this.parameters.clear();
this.blocks.clear();
this.parameters.addAll(first.parameters);
this.parameters.retainAll(second.parameters);
Iterator<String> it1 = first.blocks.iterator();
Iterator<String> it2 = second.blocks.iterator();
while (it1.hasNext() && it2.hasNext()) {
String b1 = it1.next();
String b2 = it2.next();
if (b1.equals(b2)) {
this.blocks.push(b1);
} else {
break;
}
}
}
@Override
public String toString() {
String r = "";
for(int i=0;i!=blocks.size();++i) {
if(i != 0) {
r += " :> ";
}
r = r + blocks.get(i);
}
return r;
}
public final static LifetimeRelation EMPTY = new LifetimeRelation();
}