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

org.opalj.constraints.NumericConstraints.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package constraints

import scala.annotation.switch

/**
 * Enumeration of all possible relations/constraints between two arbitrary numeric values.
 *
 * @author Michael Eichberg
 */
object NumericConstraints extends Enumeration(1) {

    final val LT = 1
    final val < : Value = Value(LT, "<")
    final val LE = 2
    final val <= : Value = Value(LE, "<=")

    final val GT = 3
    final val > : Value = Value(GT, ">")
    final val GE = 4
    final val >= : Value = Value(GE, ">=")

    final val EQ = 5
    final val == : Value = Value(EQ, "==")
    final val NE = 6
    final val != : Value = Value(NE, "!=")

    nextId = 7

    /**
     * Returns the relation when we swap the operands.
     *
     * E.g., `inverse(>) = <`; `x < y === y > x`.
     */
    def inverse(relation: Value): Value = {
        (relation.id: @switch) match {
            case LT ⇒ >
            case LE ⇒ >=
            case GT ⇒ <
            case GE ⇒ <=
            case EQ ⇒ ==
            case NE ⇒ !=
        }
    }

    /**
     * Calculates the constraint that is in effect if both constraints need to be
     * satisfied at the same time. E.g., the result of combining "less than" with
     * "equal or less than" is "less than". However, the combination of "less than"
     * with "greater than" would throw an exception.
     *
     * @note This a '''narrowing''' operation.
     *
     * @return The combined constraint.
     */
    @throws[IncompatibleNumericConstraints]("if the combination doesn't make sense")
    def combine(c1: Value, c2: Value): Value = {
        (c1.id: @switch) match {
            case LT ⇒
                (c2.id: @switch) match {
                    case LT ⇒ <
                    case LE ⇒ <
                    case NE ⇒ <
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }

            case LE ⇒
                (c2.id: @switch) match {
                    case LT ⇒ <
                    case LE ⇒ <=
                    case GE ⇒ ==
                    case EQ ⇒ ==
                    case NE ⇒ <
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }

            case GT ⇒
                (c2.id: @switch) match {
                    case GT ⇒ >
                    case GE ⇒ >
                    case NE ⇒ >
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }

            case GE ⇒
                (c2.id: @switch) match {
                    case LE ⇒ ==
                    case GT ⇒ >
                    case GE ⇒ >=
                    case EQ ⇒ ==
                    case NE ⇒ >
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }

            case EQ ⇒
                (c2.id: @switch) match {
                    case LE ⇒ ==
                    case GE ⇒ ==
                    case EQ ⇒ ==
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }

            case NE ⇒
                (c2.id: @switch) match {
                    case LT ⇒ <
                    case LE ⇒ <
                    case GT ⇒ >
                    case GE ⇒ >
                    case NE ⇒ !=
                    case _  ⇒ throw new IncompatibleNumericConstraints(c1, c2)
                }
        }
    }

    /**
     * Joins the given constraints. I.e., returns the constraint that still has to
     * hold if either `c1` or `c2` holds. E.g., the result of joining "<" with "==" with
     * is "<=".
     *
     * @note This is a '''widening''' operation.
     */
    def join(c1: Value, c2: Value): Option[Value] = {
        (c1.id: @switch) match {
            case LT ⇒
                (c2.id: @switch) match {
                    case LT ⇒ Some(<)
                    case LE ⇒ Some(<=)
                    case GT ⇒ Some(!=)
                    case GE ⇒ None
                    case NE ⇒ Some(!=)
                    case EQ ⇒ Some(<=)
                }

            case LE ⇒
                (c2.id: @switch) match {
                    case LT ⇒ Some(<=)
                    case LE ⇒ Some(<=)
                    case GT ⇒ None
                    case GE ⇒ None
                    case NE ⇒ None
                    case EQ ⇒ Some(<=)
                }

            case GT ⇒
                (c2.id: @switch) match {
                    case LT ⇒ Some(!=)
                    case LE ⇒ None
                    case GT ⇒ Some(>)
                    case GE ⇒ Some(>=)
                    case NE ⇒ Some(!=)
                    case EQ ⇒ Some(>=)
                }

            case GE ⇒
                (c2.id: @switch) match {
                    case LT ⇒ None
                    case LE ⇒ None
                    case GT ⇒ Some(>=)
                    case GE ⇒ Some(>=)
                    case NE ⇒ None
                    case EQ ⇒ Some(>=)
                }

            case EQ ⇒
                (c2.id: @switch) match {
                    case LT ⇒ Some(<=)
                    case LE ⇒ Some(<=)
                    case GT ⇒ Some(>=)
                    case GE ⇒ Some(>=)
                    case NE ⇒ None
                    case EQ ⇒ Some(==)
                }

            case NE ⇒
                (c2.id: @switch) match {
                    case LT ⇒ Some(!=)
                    case LE ⇒ None
                    case GT ⇒ Some(!=)
                    case GE ⇒ None
                    case NE ⇒ Some(!=)
                    case EQ ⇒ None
                }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy