/*************************
 * Owen Sullivan
 * CPSC 2310 Fall 22
 * Lab 11
 * Username: opsulli
 * Instructor: Dr. Yvon Feaster
*************************/

#include "functions.h"

/* 
 * absValue - returns the absolute value of x
 *   Example: absValue(-1) = 1.
 *   You may assume -TMax <= x <= TMax
 *   Legal ops: ! ~ & ^ | + << >>
 */
int absValue(int val) {

    // Assuming a 32-bit signed integer, 
    // shift the value right by 31 to create a bitwise mask 
    // equivalent to 11111111 for negative numbers or 
    // 00000000 for positive numbers
    int mask = val >> 31;

    // Add the value to the mask, then XOR the sum
    return ((mask + val) ^ mask);

}

/* 
 * binaryAnd - x&y using only ~ and | 
 *   Example: binaryAnd(6, 5) = 4
 *   Legal ops: ~ |
 */
int binaryAnd(int left, int right) {

    // Take the NOT of the OR of the NOT of the first value and the NOT 
    // of the second value
    return (~((~left) | (~right)));

}

/* 
 * binaryNotOr - ~(x|y) using only ~ and & 
 *   Example: binaryNotOr(0x6, 0x5) = 0xFFFFFFF8
 *   Legal ops: ~ &
 */
int binaryNotOr(int left, int right) {

    // Take the AND of the NOT of the first value and the NOT of the second 
    // value
    return ((~left) & (~right));

}

/* 
 * binaryOr - x|y using only ~ and & 
 *   Example: binaryOr(6, 5) = 7
 *   Legal ops: ~ &
 */
int binaryOr(int left, int right) {

    // Take the NOT of the AND of the NOT of the first value and the NOT 
    // of the second value
    return (~((~left) & (~right)));

}

/* 
 * binaryXor - x^y using only ~ and & 
 *   Example: binaryXor(4, 5) = 1
 *   Legal ops: ~ &
 */
int binaryXor(int left, int right) {

    // Take the AND of the NOT of the first value and the second value
    int andResult1 = ~left & right;
    // Take the AND of the first value and the NOT of the second value
    int andResult2 = left & ~right;

    // Take the NOT of the AND of the NOT of the first AND result 
    // and the NOT of the second AND result
    return (~(~andResult1 & ~andResult2));

}

/*
 * unsignedAddOk - determines if two unsigned int's can be added
 * without an overflow
 * Legal ops: all
 */
int unsignedAddOK(unsigned int left, unsigned int right) {

    // Add the two unsigned ints
    unsigned int sum = left + right;

    // If the sum is greater than equal to both the left and right, 
    // the addition operation has not overflowed (returns 1). Otherwise, 
    // returns 0
    return (sum >= left && sum >= right);

}

/*
 * twosAddOk - determines if two int's can be added
 * without an overflow
 * Legal ops: all
 */
int twosAddOk(int left, int right) {

    // Add the two ints
    int sum = left + right;

    // If both operands are positive but the sum is not, there is an 
    // overflow error
    if (left > 0 && right > 0 && sum <= 0) {

        return 0;

      // If both operands are negative but the sum is not, there is an 
      // overflow error
    } else if (left < 0 && right < 0 && sum >= 0) {

        return 0;

      // All other cases have no overflow
    } else {

        return 1;

    }

}

/*
 *  int twosSubOk - Determine whether arguments can be subracted 
 *  without overflow
 *  Legal ops: all
 */
int twosSubtractOK(int left, int right) {

    // If the subtrahend is positive and the minuend is less than the sum of 
    // the minimum possible integer and the subtrahend, there's an overflow
    if (right > 0 && left < INT32_MIN + right) {

        return 0;

      // If the subtrahend is negative and the minuend is greater than the sum 
      // of the maximum possible integer and the subtrahend, there's an overflow
    } else if (right < 0 && left > INT32_MAX + right) {

        return 0;

      // All other cases have no overflow
    } else {

        return 1;

    }

}