Library to allo USB PTP device to be hosted by the mbed platform

Dependents:   class_project_main

PIMA15740/uint128_t..h

Committer:
jakowisp
Date:
2013-10-07
Revision:
11:3b072cf16df8
Parent:
10:fc1cb68fc91e

File content as of revision 11:3b072cf16df8:

/*
uint128_t.h
An unsigned 128 bit integer library for C++
By Jason Lee @ calccrypto@yahoo.com
with much help from Auston Sterling
 
And thanks to Stefan Deigmüller for finding
a bug in operator*.
*/
 
#ifndef UINT128_T_H
#define UINT128_T_H
 
#include <cstdlib>
#include <iostream>
#include <stdint.h>
 
class uint128_t{
    private:
        uint64_t UPPER, LOWER;
 
    public:
        // Constructors
        uint128_t(){
            UPPER = 0;
            LOWER = 0;
        }
 
        template <typename T>
        uint128_t(T rhs){
            UPPER = 0;
            LOWER = (uint64_t) rhs;
        }
 
        template <typename S, typename T>
        uint128_t(const S upper_rhs, const T lower_rhs){
            UPPER = (uint64_t) upper_rhs;
            LOWER = (uint64_t) lower_rhs;
        }
 
        uint128_t(const uint128_t & rhs){
            UPPER = rhs.UPPER;
            LOWER = rhs.LOWER;
        }
 
        //  RHS input args only
 
        // Assignment Operator
        template <typename T> uint128_t operator=(T rhs){
            UPPER = 0;
            LOWER = (uint64_t) rhs;
            return *this;
        }
 
        uint128_t operator=(uint128_t rhs){
            UPPER = rhs.UPPER;
            LOWER = rhs.LOWER;
            return *this;
        }
 
        // Typecast Operators
        operator bool(){
            return (bool) (UPPER | LOWER);
        }
 
        operator char(){
            return (char) LOWER;
        }
 
        operator int(){
            return (int) LOWER;
        }
 
        operator uint8_t(){
            return (uint8_t) LOWER;
        }
 
        operator uint16_t(){
            return (uint16_t) LOWER;
        }
 
        operator uint32_t(){
            return (uint32_t) LOWER;
        }
 
        operator uint64_t(){
            return LOWER;
        }
 
        // Bitwise Operators
        template <typename T> uint128_t operator&(T rhs){
            return uint128_t(0, LOWER & (uint64_t) rhs);
        }
 
        uint128_t operator&(uint128_t rhs){
            return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER);
        }
 
        template <typename T> uint128_t operator|(T rhs){
            return uint128_t(UPPER, LOWER | (uint64_t) rhs);
        }
 
        uint128_t operator|(uint128_t rhs){
            return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER);
        }
 
        template <typename T> uint128_t operator^(T rhs){
            return uint128_t(UPPER, LOWER ^ (uint64_t) rhs);
        }
 
        uint128_t operator^(uint128_t rhs){
            return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER);
        }
 
        template <typename T> uint128_t operator&=(T rhs){
            UPPER = 0;
            LOWER &= rhs;
            return *this;
        }
 
        uint128_t operator&=(uint128_t rhs){
            UPPER &= rhs.UPPER;
            LOWER &= rhs.LOWER;
            return *this;
        }
 
        template <typename T> uint128_t operator|=(T rhs){
            LOWER |= (uint64_t) rhs;
            return *this;
        }
 
        uint128_t operator|=(uint128_t rhs){
            UPPER |= rhs.UPPER;
            LOWER |= rhs.LOWER;
            return *this;
        }
 
        template <typename T> uint128_t operator^=(T rhs){
            LOWER ^= (uint64_t) rhs;
            return *this;
        }
 
        uint128_t operator^=(const uint128_t rhs){
            UPPER ^= rhs.UPPER;
            LOWER ^= rhs.LOWER;
            return *this;
        }
 
        uint128_t operator~(){
            return uint128_t(~UPPER, ~LOWER);
        }
 
        // Bit Shift Operators
        template <typename T>
        uint128_t operator<<(const T shift){
            if (shift >= 128)
                return uint128_t(0, 0);
            else if (shift == 64)
                return uint128_t(LOWER, 0);
            else if (shift == 0)
                return *this;
            else if (shift < 64)
                return uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift);
            else if ((128 > shift) && (shift > 64))
                return uint128_t(LOWER << (shift - 64), 0);
            else
                return uint128_t(0);
        }
 
        template <typename T>
        uint128_t operator>>(const T shift){
            if (shift >= 128)
                return uint128_t(0, 0);
            else if (shift == 64)
                return uint128_t(0, UPPER);
            else if (shift == 0)
                return *this;
            else if (shift < 64)
                return uint128_t(UPPER >> shift, (UPPER << (64 - shift)) + (LOWER >> shift));
            else if ((128 > shift) && (shift > 64))
                return uint128_t(0, (UPPER >> (shift - 64)));
            else
                return uint128_t(0);
        }
 
        uint128_t operator<<=(int shift){
            *this = *this << shift;
            return *this;
        }
 
        uint128_t operator>>=(int shift){
            *this = *this >> shift;
            return *this;
        }
 
        // Logical Operators
        bool operator!(){
            return !(bool) (UPPER | LOWER);
        }
 
        template <typename T> bool operator&&(T rhs){
            return (bool) *this && rhs;
        }
 
        template <typename T> bool operator&&(uint128_t rhs){
            return (bool) *this && (bool) rhs;
        }
 
        template <typename T> bool operator||(T rhs){
            return ((bool) *this) || rhs;
 
        }
 
        template <typename T> bool operator||(uint128_t rhs){
            return ((bool) *this) || (bool) rhs;
        }
 
        // Comparison Operators
        template <typename T> bool operator==(T rhs){
            return (!UPPER && (LOWER == (uint64_t) rhs));
        }
 
        bool operator==(uint128_t rhs){
            return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER));
        }
 
        template <typename T> bool operator!=(T rhs){
            return (UPPER | (LOWER != (uint64_t) rhs));
        }
 
        bool operator!=(uint128_t rhs){
            return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER));
        }
 
        template <typename T> bool operator>(T rhs){
            if (UPPER)
                return true;
            return (LOWER > (uint64_t) rhs);
        }
 
        bool operator>(uint128_t rhs){
            if (UPPER == rhs.UPPER)
                return (LOWER > rhs.LOWER);
            if (UPPER > rhs.UPPER)
                return true;
            return false;
        }
 
        template <typename T> bool operator<(T rhs){
            if  (!UPPER)
                return (LOWER < (uint64_t) rhs);
            return false;
        }
 
        bool operator<(uint128_t rhs){
            if (UPPER == rhs.UPPER)
                return (LOWER < rhs.LOWER);
            if (UPPER < rhs.UPPER)
                return true;
            return false;
        }
 
        template <typename T> bool operator>=(T rhs){
            return ((*this > rhs) | (*this == rhs));
        }
 
        bool operator>=(uint128_t rhs){
            return ((*this > rhs) | (*this == rhs));
        }
 
        template <typename T> bool operator<=(T rhs){
            return ((*this < rhs) | (*this == rhs));
        }
 
        bool operator<=(uint128_t rhs){
            return ((*this < rhs) | (*this == rhs));
        }
 
        // Arithmetic Operators
        template <typename T> uint128_t operator+(T rhs){
            return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs);
        }
 
        uint128_t operator+(uint128_t rhs){
            return uint128_t(rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER);
        }
 
        template <typename T> uint128_t operator+=(T rhs){
            UPPER = UPPER + ((LOWER + rhs) < LOWER);
            LOWER = LOWER + rhs;
            return *this;
        }
 
        uint128_t operator+=(uint128_t rhs){
            UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER);
            LOWER = LOWER + rhs.LOWER;
            return *this;
        }
 
        template <typename T> uint128_t  operator-(T rhs){
            return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs));
        }
 
        uint128_t  operator-(uint128_t rhs){
            return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER);
        }
 
        template <typename T> uint128_t operator-=(T rhs){
            *this = *this - rhs;
            return *this;
        }
 
        uint128_t operator-=(uint128_t rhs){
            *this = *this - rhs;
            return *this;
        }
 
        template <typename T> uint128_t operator*(T rhs){
            return *this * uint128_t(rhs);
        }
 
        uint128_t operator*(uint128_t rhs){
            // split values into 4 32-bit parts
            uint64_t top[4] = {UPPER >> 32, UPPER % 0x100000000ULL, LOWER >> 32, LOWER % 0x100000000ULL};
            uint64_t bottom[4] = {rhs.upper() >> 32, rhs.upper() % 0x100000000ULL, rhs.lower() >> 32, rhs.lower() % 0x100000000ULL};
            uint64_t products[4][4];
 
            for(int y = 3; y > -1; y--)
                for(int x = 3; x > -1; x--){
                    products[3 - x][y] = top[x] * bottom[y];
            }
 
            // initial row
            uint64_t fourth32 = products[0][3] % 0x100000000ULL;
            uint64_t third32 = products[0][2] % 0x100000000ULL + (products[0][3] >> 32);
            uint64_t second32 = products[0][1] % 0x100000000ULL + (products[0][2] >> 32);
            uint64_t first32 = products[0][0] % 0x100000000ULL + (products[0][1] >> 32);
 
            // second row
            third32 += products[1][3] % 0x100000000ULL;
            second32 += (products[1][2] % 0x100000000ULL) + (products[1][3] >> 32);
            first32 += (products[1][1] % 0x100000000ULL) + (products[1][2] >> 32);
 
            // third row
            second32 += products[2][3] % 0x100000000ULL;
            first32 += (products[2][2] % 0x100000000ULL) + (products[2][3] >> 32);
 
            // fourth row
            first32 += products[3][3] % 0x100000000ULL;
 
            // combines the values, taking care of carry over
            return uint128_t(first32 << 32, 0) + uint128_t(third32 >> 32, third32 << 32) + uint128_t(second32, 0) + uint128_t(fourth32);
        }
 
        template <typename T> uint128_t operator*=(T rhs){
            *this = *this * uint128_t(rhs);
            return *this;
        }
 
        uint128_t operator*=(uint128_t rhs){
            *this = *this * rhs;
            return *this;
        }
 
        template <typename T> uint128_t operator/(T rhs){
            return *this / uint128_t(rhs);
        }
 
        uint128_t operator/(uint128_t rhs){
            // Save some calculations /////////////////////
            if (rhs == 0){
                std::cout << "Error: division or modulus by zero" << std::endl;
                exit(1);
            }
            if (rhs == 1)
                return *this;
            if (*this == rhs)
                return uint128_t(1);
            if ((*this == 0) | (*this < rhs))
                return uint128_t(0);
            // Checks for divisors that are powers of two
            uint16_t s = 0;
            uint128_t copyd(rhs);
            while ((copyd.LOWER & 1) == 0){
                copyd >>= 1;
                s++;
            }
            if (copyd == 1)
                return *this >> s;
            ////////////////////////////////////////////////
            uint128_t copyn(*this), quotient = 0;
            while (copyn >= rhs){
                uint128_t copyd(rhs), temp(1);
                // shift the divsor to match the highest bit
                while ((copyn >> 1) > copyd){
                    copyd <<= 1;
                    temp <<= 1;
                }
                copyn -= copyd;
                quotient += temp;
            }
            return quotient;
        }
 
        template <typename T> uint128_t operator/=(T rhs){
            *this = *this / uint128_t(rhs);
            return *this;
        }
 
        uint128_t operator/=(uint128_t rhs){
            *this = *this / rhs;
            return *this;
        }
 
        template <typename T> uint128_t operator%(T rhs){
            return *this - (rhs * (*this / rhs));
        }
 
        uint128_t operator%(uint128_t rhs){
            return *this - (rhs * (*this / rhs));
        }
 
        template <typename T> uint128_t operator%=(T rhs){
            *this = *this % uint128_t(rhs);
            return *this;
        }
 
        uint128_t operator%=(uint128_t rhs){
            *this = *this % rhs;
            return *this;
        }
 
        // Increment Operator
        uint128_t operator++(){
            *this += 1;
            return *this;
        }
 
        uint128_t operator++(int){
            uint128_t temp(*this);
            ++*this;
            return temp;
        }
 
        // Decrement Operator
        uint128_t operator--(){
            *this -= 1;
            return *this;
        }
 
        uint128_t operator--(int){
            uint128_t temp(*this);
            --*this;
            return temp;
        }
 
        // get private values
        uint64_t upper(){
            return UPPER;
        }
 
        uint64_t lower(){
            return LOWER;
        }
};
// lhs type T as first arguemnt
 
// Bitwise Operators
template <typename T> T operator&(T lhs, uint128_t rhs){
    T out = lhs & (T) rhs.lower();
    return out;
}
 
template <typename T> T operator|(T lhs, uint128_t rhs){
    T out = lhs | (T) rhs.lower();
    return out;
}
 
template <typename T> T operator^(T lhs, uint128_t rhs){
    T out = lhs ^ (T) rhs.lower();
    return out;
}
 
template <typename T> T operator&=(T & lhs, uint128_t rhs){
    lhs &= (T) rhs.lower();
    return lhs;
}
 
template <typename T> T operator|=(T & lhs, uint128_t rhs){
    lhs |= (T) rhs.lower();
    return lhs;
}
 
template <typename T> T operator^=(T & lhs, uint128_t rhs){
    lhs ^= (T) rhs.lower();
    return lhs;
}
 
// Comparison Operators
template <typename T> bool operator==(T lhs, uint128_t rhs){
    return (!rhs.upper() && ((uint64_t) lhs == rhs.lower()));
}
 
template <typename T> bool operator!=(T lhs, uint128_t rhs){
    return (rhs.upper() | ((uint64_t) lhs != rhs.lower()));
}
 
template <typename T> bool operator>(T lhs, uint128_t rhs){
    if (rhs.upper())
        return false;
    return ((uint64_t) lhs > rhs.lower());
}
 
template <typename T> bool operator<(T lhs, uint128_t rhs){
    if (rhs.upper())
        return true;
    return ((uint64_t) lhs < rhs.lower());
}
 
template <typename T> bool operator>=(T lhs, uint128_t rhs){
    if (rhs.upper())
        return false;
    return ((uint64_t) lhs >= rhs.lower());
}
 
template <typename T> bool operator<=(T lhs, uint128_t rhs){
    if (rhs.upper())
        return true;
    return ((uint64_t) lhs <= rhs.lower());
}
 
// Arithmetic Operators
template <typename T> T operator+(T lhs, uint128_t rhs){
    return (T) (rhs + lhs);
}
 
template <typename T> T & operator+=(T & lhs, uint128_t rhs){
    lhs = (T) (rhs + lhs);
    return lhs;
}
 
template <typename T> T operator-(T lhs, uint128_t rhs){
    return (T) (rhs - lhs);
}
 
template <typename T> T & operator-=(T & lhs, uint128_t rhs){
    lhs = (T) (rhs - lhs);
    return lhs;
}
 
template <typename T> T operator*(T lhs, uint128_t rhs){
    return lhs * rhs.lower();
}
 
template <typename T> T & operator*=(T & lhs, uint128_t rhs){
    lhs = (T) (rhs.lower() * lhs);
    return lhs;
}
 
template <typename T> T operator/(T lhs, uint128_t rhs){
    return (T) (uint128_t(lhs) / rhs);
}
 
template <typename T> T & operator/=(T & lhs, uint128_t rhs){
    lhs = (T) (uint128_t(lhs) / rhs);
    return lhs;
}
 
template <typename T> T operator%(T lhs, uint128_t rhs){
    return (T) (uint128_t(lhs) % rhs);
}
 
template <typename T> T & operator%=(T & lhs, uint128_t rhs){
    lhs = (T) (uint128_t(lhs) % rhs);
    return lhs;
}
 
// IO Operator
std::ostream & operator<<(std::ostream & stream, uint128_t rhs){
    std::string out = "";
    if (rhs == 0)
        out = "0";
    else {
        int div = 10;
        if (stream.flags() & stream.oct)
            div = 8;
        if (stream.flags() & stream.dec)
            div = 10;
        if (stream.flags() & stream.hex)
            div = 16;
        while (rhs > 0){
            out = "0123456789abcdef"[size_t(rhs % div)] + out;
            rhs /= div;
        }
    }
    stream << out;
    return stream;
}
 
#endif // UINT128_T_H