BasicMultiset.java

package edu.udel.cis.vsl.abc.front.c.astgen;

import java.util.HashMap;
import java.util.Map;

import edu.udel.cis.vsl.abc.ast.type.IF.StandardBasicType.BasicTypeKind;
import edu.udel.cis.vsl.abc.front.c.parse.CivlCParser;

/**
 * A BasicMultiset represents a set with multiplicity whose elements belong to
 * the 10 basic type specifier keywords: CHAR, SHORT, INT, LONG, FLOAT, DOUBLE,
 * SIGNED, UNSIGNED, BOOL, COMPLEX. These words can be used in certain
 * combinations to denote the basic types. The order in which the words appear
 * in a declaration does not matter, but multiplicty does (since, for example, a
 * long long int is different from a long int). Hence the C11 Standard uses the
 * mathematical notion of "multiset" (set with multiplicities) to define the
 * ways to name these types. Also, several different multisets may represent the
 * same basic type.
 * 
 * @author siegel
 * 
 */
public class BasicMultiset {

	// The 10 basic type specifier keywords:

	public final static int CHAR = CivlCParser.CHAR;
	public final static int SHORT = CivlCParser.SHORT;
	public final static int INT = CivlCParser.INT;
	public final static int LONG = CivlCParser.LONG;
	public final static int FLOAT = CivlCParser.FLOAT;
	public final static int DOUBLE = CivlCParser.DOUBLE;
	public final static int SIGNED = CivlCParser.SIGNED;
	public final static int UNSIGNED = CivlCParser.UNSIGNED;
	public final static int BOOL = CivlCParser.BOOL;
	public final static int COMPLEX = CivlCParser.COMPLEX;

	// Extra real type basic type specifier keyword
	public final static int REAL = CivlCParser.REAL;

	// The 18 basic multiset classes and their variants...

	public final static BasicMultiset CHAR_TYPE = new BasicMultiset(CHAR);
	public final static BasicMultiset SIGNED_CHAR_TYPE = new BasicMultiset(
			SIGNED, CHAR);
	public final static BasicMultiset UNSIGNED_CHAR_TYPE = new BasicMultiset(
			UNSIGNED, CHAR);
	public final static BasicMultiset SHORT_TYPE = new BasicMultiset(SHORT);
	public final static BasicMultiset SHORT_TYPE_v1 = new BasicMultiset(SIGNED,
			SHORT);
	public final static BasicMultiset SHORT_TYPE_v2 = new BasicMultiset(SHORT,
			INT);
	public final static BasicMultiset SHORT_TYPE_v3 = new BasicMultiset(SIGNED,
			SHORT, INT);
	public final static BasicMultiset UNSIGNED_SHORT_TYPE = new BasicMultiset(
			UNSIGNED, SHORT);
	public final static BasicMultiset UNSIGNED_SHORT_TYPE_v1 = new BasicMultiset(
			UNSIGNED, SHORT, INT);
	public final static BasicMultiset INT_TYPE = new BasicMultiset(INT);
	public final static BasicMultiset INT_TYPE_v1 = new BasicMultiset(SIGNED);
	public final static BasicMultiset INT_TYPE_v2 = new BasicMultiset(SIGNED,
			INT);
	public final static BasicMultiset UNSIGNED_TYPE = new BasicMultiset(
			UNSIGNED);
	public final static BasicMultiset UNSIGNED_TYPE_v1 = new BasicMultiset(
			UNSIGNED, INT);
	public final static BasicMultiset LONG_TYPE = new BasicMultiset(LONG);
	public final static BasicMultiset LONG_TYPE_v1 = new BasicMultiset(SIGNED,
			LONG);
	public final static BasicMultiset LONG_TYPE_v2 = new BasicMultiset(LONG,
			INT);
	public final static BasicMultiset LONG_TYPE_v3 = new BasicMultiset(SIGNED,
			LONG, INT);
	public final static BasicMultiset UNSIGNED_LONG_TYPE = new BasicMultiset(
			UNSIGNED, LONG);
	public final static BasicMultiset UNSIGNED_LONG_TYPE_v1 = new BasicMultiset(
			UNSIGNED, LONG, INT);
	public final static BasicMultiset LONG_LONG_TYPE = new BasicMultiset(LONG,
			LONG);
	public final static BasicMultiset LONG_LONG_TYPE_v1 = new BasicMultiset(
			SIGNED, LONG, LONG);
	public final static BasicMultiset LONG_LONG_TYPE_v2 = new BasicMultiset(
			LONG, LONG, INT);
	public final static BasicMultiset LONG_LONG_TYPE_v3 = new BasicMultiset(
			SIGNED, LONG, LONG, INT);
	public final static BasicMultiset UNSIGNED_LONG_LONG_TYPE = new BasicMultiset(
			UNSIGNED, LONG, LONG);
	public final static BasicMultiset UNSIGNED_LONG_LONG_TYPE_v1 = new BasicMultiset(
			UNSIGNED, LONG, LONG, INT);
	public final static BasicMultiset FLOAT_TYPE = new BasicMultiset(FLOAT);
	public final static BasicMultiset DOUBLE_TYPE = new BasicMultiset(DOUBLE);
	public final static BasicMultiset LONG_DOUBLE_TYPE = new BasicMultiset(
			LONG, DOUBLE);
	public final static BasicMultiset BOOL_TYPE = new BasicMultiset(BOOL);
	public final static BasicMultiset FLOAT_COMPLEX_TYPE = new BasicMultiset(
			FLOAT, COMPLEX);
	public final static BasicMultiset DOUBLE_COMPLEX_TYPE = new BasicMultiset(
			DOUBLE, COMPLEX);
	public final static BasicMultiset LONG_DOUBLE_COMPLEX_TYPE = new BasicMultiset(
			LONG, DOUBLE, COMPLEX);
	public final static BasicMultiset REAL_TYPE = new BasicMultiset(REAL);

	/**
	 * A map used to specify the "acceptable" multisets and to map any
	 * acceptable multiset to its canonical name. The keys in this map are all
	 * the acceptable multisets. The value associated to a key is the name of
	 * the basic type it represents, from the enumerated type BasicTypeKind.
	 */
	public final static Map<BasicMultiset, BasicTypeKind> acceptableMultisetMap = makeAcceptableMultisetMap();

	/**
	 * Creates and initializes the acceptableMultisetMap. The map is a
	 * constant---it never changes after this.
	 * 
	 * @return the acceptable multiset map
	 */
	public final static Map<BasicMultiset, BasicTypeKind> makeAcceptableMultisetMap() {
		Map<BasicMultiset, BasicTypeKind> map = new HashMap<BasicMultiset, BasicTypeKind>();

		map.put(CHAR_TYPE, BasicTypeKind.CHAR);
		map.put(SIGNED_CHAR_TYPE, BasicTypeKind.SIGNED_CHAR);
		map.put(UNSIGNED_CHAR_TYPE, BasicTypeKind.UNSIGNED_CHAR);
		map.put(SHORT_TYPE, BasicTypeKind.SHORT);
		map.put(SHORT_TYPE_v1, BasicTypeKind.SHORT);
		map.put(SHORT_TYPE_v2, BasicTypeKind.SHORT);
		map.put(SHORT_TYPE_v3, BasicTypeKind.SHORT);
		map.put(UNSIGNED_SHORT_TYPE, BasicTypeKind.UNSIGNED_SHORT);
		map.put(UNSIGNED_SHORT_TYPE_v1, BasicTypeKind.UNSIGNED_SHORT);
		map.put(INT_TYPE, BasicTypeKind.INT);
		map.put(INT_TYPE_v1, BasicTypeKind.INT);
		map.put(INT_TYPE_v2, BasicTypeKind.INT);
		map.put(UNSIGNED_TYPE, BasicTypeKind.UNSIGNED);
		map.put(UNSIGNED_TYPE_v1, BasicTypeKind.UNSIGNED);
		map.put(LONG_TYPE, BasicTypeKind.LONG);
		map.put(LONG_TYPE_v1, BasicTypeKind.LONG);
		map.put(LONG_TYPE_v2, BasicTypeKind.LONG);
		map.put(LONG_TYPE_v3, BasicTypeKind.LONG);
		map.put(UNSIGNED_LONG_TYPE, BasicTypeKind.UNSIGNED_LONG);
		map.put(UNSIGNED_LONG_TYPE_v1, BasicTypeKind.UNSIGNED_LONG);
		map.put(LONG_LONG_TYPE, BasicTypeKind.LONG_LONG);
		map.put(LONG_LONG_TYPE_v1, BasicTypeKind.LONG_LONG);
		map.put(LONG_LONG_TYPE_v2, BasicTypeKind.LONG_LONG);
		map.put(LONG_LONG_TYPE_v3, BasicTypeKind.LONG_LONG);
		map.put(UNSIGNED_LONG_LONG_TYPE, BasicTypeKind.UNSIGNED_LONG_LONG);
		map.put(UNSIGNED_LONG_LONG_TYPE_v1, BasicTypeKind.UNSIGNED_LONG_LONG);
		map.put(FLOAT_TYPE, BasicTypeKind.FLOAT);
		map.put(DOUBLE_TYPE, BasicTypeKind.DOUBLE);
		map.put(LONG_DOUBLE_TYPE, BasicTypeKind.LONG_DOUBLE);
		map.put(BOOL_TYPE, BasicTypeKind.BOOL);
		map.put(FLOAT_COMPLEX_TYPE, BasicTypeKind.FLOAT_COMPLEX);
		map.put(DOUBLE_COMPLEX_TYPE, BasicTypeKind.DOUBLE_COMPLEX);
		map.put(LONG_DOUBLE_COMPLEX_TYPE, BasicTypeKind.LONG_DOUBLE_COMPLEX);
		map.put(REAL_TYPE, BasicTypeKind.REAL);
		return map;
	}

	/**
	 * Given any BasicMultiset, this returns null if the multiset is not
	 * acceptable (i.e., is not one of those specified in the C11 Standard as
	 * defining a basic type), else returns the name of the basic type it
	 * represents.
	 * 
	 * @param set
	 *            a multiset of type specifier keywords
	 * @return null or the name of the basic type represented
	 */
	public final static BasicTypeKind getBasicTypeKind(BasicMultiset set) {
		return acceptableMultisetMap.get(set);
	}

	// instance variables...

	int charCount = 0;
	int shortCount = 0;
	int intCount = 0;
	int longCount = 0;
	int floatCount = 0;
	int doubleCount = 0;
	int realCount = 0;
	int signedCount = 0;
	int unsignedCount = 0;
	int boolCount = 0;
	int complexCount = 0;

	/**
	 * Creates new multiset with the given elements.
	 * 
	 * @param elements
	 *            array of ints belonging to the set of 11 basic keywords
	 */
	BasicMultiset(int[] elements) {
		for (int element : elements)
			add(element);
	}

	/**
	 * Creates new empty multiset.
	 */
	BasicMultiset() {
	}

	/**
	 * Creates new multiset with 1 element.
	 * 
	 * @param element0
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 */
	BasicMultiset(int element0) {
		add(element0);
	}

	/**
	 * Creates new multiset with 2 elements.
	 * 
	 * @param element0
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * @param element1
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 */
	BasicMultiset(int element0, int element1) {
		add(element0);
		add(element1);
	}

	/**
	 * Creates new multiset with 3 elements.
	 * 
	 * @param element0
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * @param element1
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * 
	 * @param element2
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 */
	BasicMultiset(int element0, int element1, int element2) {
		add(element0);
		add(element1);
		add(element2);
	}

	/**
	 * Creates new multiset with 4 elements.
	 * 
	 * @param element0
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * @param element1
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * 
	 * @param element2
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 * 
	 * @param element3
	 *            one of the ints representing one of the 11 basic type
	 *            specifier keywords
	 */
	BasicMultiset(int element0, int element1, int element2, int element3) {
		add(element0);
		add(element1);
		add(element2);
		add(element3);
	}

	/**
	 * Adds one element to the multiset
	 * 
	 * @param element
	 *            one of the ints representing one of the 10 basic type
	 *            specifier keywords
	 * 
	 * @exception IllegalArgumentException
	 *                if element is not one of the 10 ints representing a basic
	 *                type specifier keyword
	 */
	public void add(int element) {
		switch (element) {
		case CHAR:
			charCount++;
			break;
		case SHORT:
			shortCount++;
			break;
		case INT:
			intCount++;
			break;
		case LONG:
			longCount++;
			break;
		case FLOAT:
			floatCount++;
			break;
		case DOUBLE:
			doubleCount++;
			break;
		case REAL:
			realCount++;
			break;
		case SIGNED:
			signedCount++;
			break;
		case UNSIGNED:
			unsignedCount++;
			break;
		case BOOL:
			boolCount++;
			break;
		case COMPLEX:
			complexCount++;
			break;
		default:
			throw new IllegalArgumentException("Unknown specifier: " + element);
		}
	}

	@Override
	public int hashCode() {
		return size();
	}

	/**
	 * Returns the number of elements of the multiset.
	 * 
	 * @return the number of elements
	 */
	public int size() {
		return charCount + shortCount + intCount + longCount + floatCount
				+ doubleCount + realCount + signedCount + unsignedCount
				+ boolCount + complexCount;
	}

	/**
	 * Does this multiset equal the given one? (I.e., have the same number of
	 * elements with same multiplicity).
	 */
	@Override
	public boolean equals(Object object) {
		if (object instanceof BasicMultiset) {
			BasicMultiset that = (BasicMultiset) object;

			return charCount == that.charCount && intCount == that.intCount
					&& longCount == that.longCount
					&& floatCount == that.floatCount
					&& doubleCount == that.doubleCount
					&& signedCount == that.signedCount
					&& unsignedCount == that.unsignedCount
					&& boolCount == that.boolCount
					&& realCount == that.realCount;
		}
		return false;
	}
}