Integers.java
package church.primitives;

import church.lang.ByteStream;

public class Integers {

    // Encoding to a stream
    public static ByteStream $encode(ByteStream stream, int a) {
        return Strings.encode(stream, Integer.toString(a));
    }

    // Equality
    public static boolean $equal(int a, int b) {
        return a == b;
    }

    // Value bounds

    public static int min_value() {
        return Integer.MIN_VALUE;
    }

    public static int max_value() {
        return Integer.MAX_VALUE;
    }

    // Ring

    public static int additive_identity() {
        return 0;
    }

    public static int $sum(int a, int b) {
        return a + b;
    }

    public static int $neg(int a) {
        return -a;
    }

    public static int $sub(int a, int b) {
        return a - b;
    }

    public static int multiplicative_identity() {
        return 1;
    }

    public static int $prd(int a, int b) {
        return a * b;
    }

    // todo port the version that is generic (in x) from the old Ring0.java
    public static int $pow(int x, int n) {
        if (n < 0) {
            throw new ArithmeticException("Negative exponent");
        }
        int result = 1;
        while (n != 0) {
            if (n % 2 != 0) {
                n      = n - 1;
                result = $prd(result, x);
            }
            n = n >>> 1;
            x = $prd(x, x);
        }
        return result;
    }

    // Ordering

    public static boolean $lt(int a, int b) {
        return a < b;
    }

    public static boolean $gt(int a, int b) {
        return a > b;
    }

    public static boolean $lte(int a, int b) {
        return a <= b;
    }

    public static boolean $gte(int a, int b) {
        return a >= b;
    }

    public static int min(int a, int b) { // todo don't copy these
        return Math.min(a, b);
    }

    public static int max(int a, int b) { // todo don't copy these
        return Math.max(a, b);
    }

    // Euclidean

    public static int quotient(int a, int b) {
        return a / b;
    }

    public static int $rem(int a, int b) {
        return a % b;
    }

    public static int sign(int a) {
        return (int) Math.signum(a);
    }

    private static int euclid(int a, int b) {
        while (b != 0) {
            int tmp = b;
            b = a % b;
            a = tmp;
        }
        return a;
    }

    public static int gcd(int a, int b) {
        return euclid(Math.abs(a), Math.abs(b));
    }

    // Divide or fail
    public static int $dof(int a, int b) {
        if (a % b != 0) {
            throw new UnsupportedOperationException(a + " /! " + b);
        }
        return a / b;
    }

    // Hash
    public static int hashCode(int a) {
        return Integer.hashCode(a); // === a
    }
}