/* * The contents of this file are subject to the Open Software License * Version 3.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.opensource.org/licenses/osl-3.0.txt * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. */ package org.mulgara.krule.rlog.ast; /** * Represents a canonicalization of a predicate. * * @created Mar 4, 2009 * @author Paula Gearon * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a> * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a> */ public class CanonicalPredicate implements Comparable<CanonicalPredicate> { /** The number of elements for a binary predicate. */ private static final int BINARY_LENGTH = 3; /** The number of elements for a unary predicate. */ private static final int UNARY_LENGTH = 2; /** The number of elements for a null predicate. */ private static final int NULL_LENGTH = 0; /** The different in ID between inverted predicates and the original predicate. */ private static final int INVERT_DIFF = 8; /** The elements of the predicate */ private PredicateParam[] elements; /** A flag to indicate that this predicate is inverted. */ private boolean invertFlag = false; /** An ID used internally for comparisons between differing types. */ private int typeId; /** * Create a new canonicalized form for a null predicate. */ CanonicalPredicate() { elements = new PredicateParam[NULL_LENGTH]; typeId = elements.length; } /** * Create a new canonicalized form for a binary predicate. * @param s The subject of the predicate. * @param p The value of the predicate. * @param o The object of the predicate. */ CanonicalPredicate(PredicateParam s, PredicateParam p, PredicateParam o) { elements = new PredicateParam[BINARY_LENGTH]; elements[0] = s; elements[1] = p; elements[2] = o; typeId = elements.length; } /** * Create a new canonicalized form for a unary predicate. * @param t The type of the predicate. * @param v The value of the predicate. */ CanonicalPredicate(PredicateParam t, PredicateParam v) { elements = new PredicateParam[UNARY_LENGTH]; elements[0] = t; elements[1] = v; typeId = elements.length; } /** * Changes this predicate to an inverted one. */ public CanonicalPredicate invert() { invertFlag = !invertFlag; typeId += invertFlag ? INVERT_DIFF : -INVERT_DIFF; return this; } /** * Changes this predicate to an inverted one. */ public boolean isInverted() { return invertFlag; } /** * Updates variables to a canonical form * @param con The object with the update state for the variables. */ public void renameVariables(VariableCanonicalizer con) { for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof Variable) { elements[i] = con.get((Variable)elements[i]); } } } /** * @see java.lang.Object#toString() */ public String toString() { StringBuilder s = new StringBuilder(); if (invertFlag) s.append("~"); switch (elements.length) { case NULL_LENGTH: s.append("<<null>>"); break; case UNARY_LENGTH: s.append(elements[0]); s.append("(").append(elements[1]).append(")"); break; case BINARY_LENGTH: s.append(elements[1]); s.append("(").append(elements[0]).append(", "); s.append(elements[2]).append(")"); break; default: throw new IllegalStateException("Illegal predicate structure. Length = " + elements.length); } return s.toString(); } /** * Tests if this predicate equals another. * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object o) { if (!(o instanceof CanonicalPredicate)) return false; CanonicalPredicate cp = (CanonicalPredicate)o; if (elements.length != cp.elements.length) return false; for (int i = 0; i < elements.length; i++) { if (!elements[i].equals(cp.elements[i])) return false; } return true; } /** * Generate a repeatable hashcode for this predicate. * @see java.lang.Object#hashCode() */ public int hashCode() { final int[] seed = new int[] { 7, 13, 17, 19 }; int result = 5; for (int i = 0; i < elements.length; i++) result += seed[i] * elements[i].hashCode(); return result; } /** * Compare this predicate to another. * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(CanonicalPredicate cpred) { if (typeId != cpred.typeId) return typeId - cpred.typeId; return compareOnElt(0, cpred); } /** * Compare this predicate, first on equivalent types, and then on type. * Order by PredicateLiteral, StringLiteral, IntegerLiteral, Var. * @param i The element being compared at this stage. * @param cpred The other CanonicalPredicate to compare against. * @return >0 if this object occurs after cpred, <0 if this object is before cpred, * and 0 if this object is equal to cpred. */ private int compareOnElt(int i, CanonicalPredicate cpred) { assert i >= 0 && i < elements.length; int typeDiff = elements[i].orderId() - cpred.elements[i].orderId(); // if the types are the same then compare if (typeDiff == 0) { int r = elements[i].compareTo(cpred.elements[i]); // if the elements are equal, then move to the next element return r == 0 && ++i < elements.length ? compareOnElt(i, cpred) : r; } return typeDiff; } }