CommonObjectFactory.java

/*******************************************************************************
 * Copyright (c) 2013 Stephen F. Siegel, University of Delaware.
 * 
 * This file is part of SARL.
 * 
 * SARL is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * SARL is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with SARL. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package edu.udel.cis.vsl.sarl.object.common;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import edu.udel.cis.vsl.sarl.IF.SARLException;
import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression;
import edu.udel.cis.vsl.sarl.IF.number.Number;
import edu.udel.cis.vsl.sarl.IF.number.NumberFactory;
import edu.udel.cis.vsl.sarl.IF.object.BooleanObject;
import edu.udel.cis.vsl.sarl.IF.object.CharObject;
import edu.udel.cis.vsl.sarl.IF.object.IntObject;
import edu.udel.cis.vsl.sarl.IF.object.NumberObject;
import edu.udel.cis.vsl.sarl.IF.object.StringObject;
import edu.udel.cis.vsl.sarl.IF.object.SymbolicObject;
import edu.udel.cis.vsl.sarl.IF.object.SymbolicSequence;
import edu.udel.cis.vsl.sarl.IF.type.SymbolicType;
import edu.udel.cis.vsl.sarl.IF.type.SymbolicTypeSequence;
import edu.udel.cis.vsl.sarl.object.IF.ObjectFactory;

/**
 * A straightforward implementation of {@link ObjectFactory}. All objects
 * returned by this factory are canonic. The methods in this factory are also
 * thread-safe.
 */
public class CommonObjectFactory implements ObjectFactory {

	// private final ReentrantReadWriteLock objectListReadWriteLock = new
	// ReentrantReadWriteLock();

	// private final Lock objectListReadLock =
	// objectListReadWriteLock.readLock();

	// private final Lock objectListWriteLock = objectListReadWriteLock
	// .writeLock();

	private ArrayList<SymbolicObject> objectList = new ArrayList<>();

	private NumberFactory numberFactory;

	private Map<SymbolicObject, SymbolicObject> objectMap;

	private BooleanObject trueObj;

	private BooleanObject falseObj;

	private IntObject zeroIntObj;

	private IntObject oneIntObj;

	private NumberObject zeroIntegerObj;

	private NumberObject zeroRealObj;

	private NumberObject oneIntegerObj;

	private NumberObject oneRealObj;

	private ObjectComparator comparator;

	private SymbolicSequence<?> emptySequence;

	public CommonObjectFactory(NumberFactory numberFactory) {
		this.numberFactory = numberFactory;
		this.comparator = new ObjectComparator(numberFactory);
	}

	@Override
	public void init() {
		assert comparator.expressionComparator() != null;
		assert comparator.typeComparator() != null;
		assert comparator.typeSequenceComparator() != null;
		this.objectMap = new HashMap<>(); // ConcurrentHashMap<>();
		this.trueObj = canonic(new CommonBooleanObject(true));
		this.falseObj = canonic(new CommonBooleanObject(false));
		this.zeroIntObj = intObject(0);
		this.oneIntObj = intObject(1);
		this.zeroIntegerObj = numberObject(numberFactory.zeroInteger());
		this.zeroRealObj = numberObject(numberFactory.zeroRational());
		this.oneIntegerObj = numberObject(numberFactory.oneInteger());
		this.oneRealObj = numberObject(numberFactory.oneRational());
		this.emptySequence = canonic(new SimpleSequence<SymbolicExpression>());
	}

	@Override
	public NumberFactory numberFactory() {
		return numberFactory;
	}

	@Override
	public void setExpressionComparator(Comparator<SymbolicExpression> c) {
		comparator.setExpressionComparator(c);
	}

	@Override
	public void setTypeComparator(Comparator<SymbolicType> c) {
		comparator.setTypeComparator(c);
	}

	@Override
	public void setTypeSequenceComparator(Comparator<SymbolicTypeSequence> c) {
		comparator.setTypeSequenceComparator(c);
	}

	@Override
	public ObjectComparator comparator() {
		return comparator;
	}

	@Override
	public <T extends SymbolicObject> T canonic(T object) {
		if (object == null)
			throw new SARLException("null object");
		if (object.isCanonic())
			return object;

		SymbolicObject result = objectMap.get(object);

		if (result == null) {
			// Set canonic id to IN_CANONIC to avoid infinite recursion when
			// canonicalizing children.
			((CommonSymbolicObject) object).setInCanonic();
			((CommonSymbolicObject) object).canonizeChildren(this);
			CommonSymbolicObject theObject = (CommonSymbolicObject) objectMap
					.putIfAbsent(object, object);

			if (theObject == null) {
				theObject = (CommonSymbolicObject) object;
				// synchronized (theObject) {
				theObject.setId(numObjects());
				// objectListWriteLock.lock();
				// try {
				objectList.add(theObject);
				// } finally {
				// objectListWriteLock.unlock();
				// }
				// theObject.notifyAll();
				// }
			} // else {
				// synchronized (theObject) {
				// while (theObject.id() < 0)
				// try {
				// theObject.wait();
				// } catch (InterruptedException e) {
				// e.printStackTrace();
				// }
				// }
				// }
			result = theObject;
		}

		@SuppressWarnings("unchecked")
		T resultCastToT = (T) result;

		return resultCastToT;
	}

	@Override
	public BooleanObject trueObj() {
		return trueObj;
	}

	@Override
	public BooleanObject falseObj() {
		return falseObj;
	}

	@Override
	public IntObject zeroIntObj() {
		return zeroIntObj;
	}

	@Override
	public IntObject oneIntObj() {
		return oneIntObj;
	}

	@Override
	public NumberObject zeroIntegerObj() {
		return zeroIntegerObj;
	}

	@Override
	public NumberObject oneIntegerObj() {
		return oneIntegerObj;
	}

	@Override
	public NumberObject zeroRealObj() {
		return zeroRealObj;
	}

	@Override
	public NumberObject oneRealObj() {
		return oneRealObj;
	}

	@Override
	public NumberObject numberObject(Number value) {
		if (value == null)
			throw new SARLException("null value");
		if (value.isInfinite())
			throw new SARLException(
					"Attempt to create an infinite number object");
		return canonic(new CommonNumberObject(value));
	}

	@Override
	public StringObject stringObject(String string) {
		if (string == null)
			throw new SARLException("null string");
		return canonic(new CommonStringObject(string));
	}

	@Override
	public IntObject intObject(int value) {
		return canonic(new CommonIntObject(value));
	}

	@Override
	public CharObject charObject(char value) {
		return canonic(new CommonCharObject(value));
	}

	@Override
	public BooleanObject booleanObject(boolean value) {
		return value ? trueObj : falseObj;
	}

	@Override
	public SymbolicObject objectWithId(int index) {
		// objectListReadLock.lock();
		// try {
		return objectList.get(index);
		// } finally {
		// objectListReadLock.unlock();
		// }
	}

	@Override
	public int numObjects() {
		// objectListReadLock.lock();
		// try {
		return objectList.size();
		// } finally {
		// objectListReadLock.unlock();
		// }
	}

	@Override
	public <T extends SymbolicObject> void canonize(T[] objectArray) {
		int n = objectArray.length;

		for (int i = 0; i < n; i++) {
			T element = objectArray[i];

			if (!element.isCanonic())
				objectArray[i] = canonic(element);
		}
	}

	@Override
	public <T extends SymbolicExpression> SymbolicSequence<T> sequence(
			Iterable<? extends T> elements) {
		return canonic(new SimpleSequence<T>(elements));
	}

	@Override
	public <T extends SymbolicExpression> SymbolicSequence<T> sequence(
			T[] elements) {
		return canonic(new SimpleSequence<T>(elements));
	}

	@Override
	public <T extends SymbolicExpression> SymbolicSequence<T> singletonSequence(
			T element) {
		return canonic(new SimpleSequence<T>(element));
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends SymbolicExpression> SymbolicSequence<T> emptySequence() {
		return (SymbolicSequence<T>) emptySequence;
	}

}