All Downloads are FREE. Search and download functionalities are using the official Maven repository.

heros.fieldsens.AccessPath Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2015 Johannes Lerch.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Johannes Lerch - initial API and implementation
 ******************************************************************************/
package heros.fieldsens;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

@SuppressWarnings("unchecked")
public class AccessPath {
	
	public static  AccessPath empty() {
		return new AccessPath();
	}
	
	private final T[] accesses;
	private final Set exclusions;
	
	public AccessPath() {
		accesses = (T[]) new Object[0];
		exclusions = Sets.newHashSet();
	}
	
	AccessPath(T[] accesses, Set exclusions) {
		this.accesses = accesses;
		this.exclusions = exclusions;
	}

	public boolean isAccessInExclusions(T fieldReference) {
		return exclusions.contains(fieldReference);
	}
	
	public boolean hasAllExclusionsOf(AccessPath accPath) {
		return exclusions.containsAll(accPath.exclusions);
	}
	
	public AccessPath append(T... fieldReferences) {
		if(fieldReferences.length == 0)
			return this;
		
		if(isAccessInExclusions(fieldReferences[0]))
			throw new IllegalArgumentException("FieldRef "+Arrays.toString(fieldReferences)+" cannot be added to "+toString());

		T[] newAccesses = Arrays.copyOf(accesses, accesses.length+fieldReferences.length);
		System.arraycopy(fieldReferences, 0, newAccesses, accesses.length, fieldReferences.length);
		return new AccessPath(newAccesses, Sets.newHashSet());
	}

	public AccessPath prepend(T fieldRef) {
		T[] newAccesses = (T[]) new Object[accesses.length+1];
		newAccesses[0] = fieldRef;
		System.arraycopy(accesses, 0, newAccesses, 1, accesses.length);
		return new AccessPath(newAccesses, exclusions);
	}

	public AccessPath removeFirst() {
		T[] newAccesses = (T[]) new Object[accesses.length-1];
		System.arraycopy(accesses, 1, newAccesses, 0, accesses.length-1);
		return new AccessPath(newAccesses, exclusions);
	}
	
	public AccessPath appendExcludedFieldReference(Collection fieldReferences) {
		HashSet newExclusions = Sets.newHashSet(fieldReferences);
		newExclusions.addAll(exclusions);
		return new AccessPath(accesses, newExclusions);
	}
	
	public AccessPath appendExcludedFieldReference(T... fieldReferences) {
		HashSet newExclusions = Sets.newHashSet(fieldReferences);
		newExclusions.addAll(exclusions);
		return new AccessPath(accesses, newExclusions);
	}

	public static enum PrefixTestResult {
		GUARANTEED_PREFIX(2), POTENTIAL_PREFIX(1), NO_PREFIX(0);
		
		private int value;

		private PrefixTestResult(int value) {
			this.value = value;
		}
		
		public boolean atLeast(PrefixTestResult minimum) {
			return value >= minimum.value;
		}
	}
	
	public PrefixTestResult isPrefixOf(AccessPath accessPath) {
		if(accesses.length > accessPath.accesses.length)
			return PrefixTestResult.NO_PREFIX;
				
		for(int i=0; i getDeltaTo(AccessPath accPath) {
		assert isPrefixOf(accPath).atLeast(PrefixTestResult.POTENTIAL_PREFIX);
		HashSet mergedExclusions = Sets.newHashSet(accPath.exclusions);
		if(accesses.length == accPath.accesses.length)
			mergedExclusions.addAll(exclusions);
		Delta delta = new Delta(Arrays.copyOfRange(accPath.accesses, accesses.length, accPath.accesses.length), mergedExclusions);
		assert (isPrefixOf(accPath).atLeast(PrefixTestResult.POTENTIAL_PREFIX) && accPath.isPrefixOf(delta.applyTo(this)) == PrefixTestResult.GUARANTEED_PREFIX) 
				|| (isPrefixOf(accPath) == PrefixTestResult.GUARANTEED_PREFIX && accPath.equals(delta.applyTo(this)));
		return delta;
	}
	
	public static class Delta {
		final T[] accesses;
		final Set exclusions;

		protected Delta(T[] accesses, Set exclusions) {
			this.accesses = accesses;
			this.exclusions = exclusions;
		}
		
		public boolean canBeAppliedTo(AccessPath accPath) {
			if(accesses.length > 0)
				return !accPath.isAccessInExclusions(accesses[0]);
			else
				return true;
		}
		
		public AccessPath applyTo(AccessPath accPath) {
			return accPath.append(accesses).appendExcludedFieldReference(exclusions);
		}
		
		@Override
		public String toString() {
			String result = accesses.length > 0 ? "."+Joiner.on(".").join(accesses) : "";
			if(!exclusions.isEmpty())
				result += "^" + Joiner.on(",").join(exclusions);
			return result;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + Arrays.hashCode(accesses);
			result = prime * result + ((exclusions == null) ? 0 : exclusions.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Delta other = (Delta) obj;
			if (!Arrays.equals(accesses, other.accesses))
				return false;
			if (exclusions == null) {
				if (other.exclusions != null)
					return false;
			} else if (!exclusions.equals(other.exclusions))
				return false;
			return true;
		}

		public static  Delta empty() {
			return new Delta((T[]) new Object[0], Sets.newHashSet());
		}
	}
	
	public AccessPath mergeExcludedFieldReferences(AccessPath accPath) {
		HashSet newExclusions = Sets.newHashSet(exclusions);
		newExclusions.addAll(accPath.exclusions);
		return new AccessPath(accesses, newExclusions);
	}
	
	public boolean canRead(T field) {
		return accesses.length > 0 && accesses[0].equals(field);
	}
	
	public boolean isEmpty() {
		return exclusions.isEmpty() && accesses.length == 0;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(accesses);
		result = prime * result + ((exclusions == null) ? 0 : exclusions.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AccessPath other = (AccessPath) obj;
		if (!Arrays.equals(accesses, other.accesses))
			return false;
		if (exclusions == null) {
			if (other.exclusions != null)
				return false;
		} else if (!exclusions.equals(other.exclusions))
			return false;
		return true;
	}

	@Override
	public String toString() {
		String result = accesses.length > 0 ? "."+Joiner.on(".").join(accesses) : "";
		if(!exclusions.isEmpty())
			result += "^" + Joiner.on(",").join(exclusions);
		return result;
	}
	
	public AccessPath removeAnyAccess() {
		if(accesses.length > 0)
			return new AccessPath((T[]) new Object[0], exclusions);
		else
			return this;
	}

	public boolean hasEmptyAccessPath() {
		return accesses.length == 0;
	}

	public T getFirstAccess() {
		return accesses[0];
	}

	Set getExclusions() {
		return exclusions;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy