Uint 128 T

/**
 * @file
 *
 * @details Implementation of 128-bit unsigned integers.
 * @note The implementation can be flagged as not completed. This header is used
 * with enough operations as a part of bigger integer types 256-bit integer.
 * @author [Ashish Daulatabad](https://github.com/AshishYUO)
 */

#include <algorithm>  /// for `std::reverse` and other operations
#include <ostream>    /// for `std::cout` overload
#include <string>     /// for `std::string`
#include <utility>    /// for `std::pair` library

#ifdef _MSC_VER
#include <intrin.h>  /// for _BitScanForward64 and __BitScanReverse64 operation
#endif

#ifndef CIPHERS_UINT128_T_HPP_
#define CIPHERS_UINT128_T_HPP_
class uint128_t;

template <>
struct std::is_integral<uint128_t> : std::true_type {};
template <>
struct std::is_arithmetic<uint128_t> : std::true_type {};
template <>
struct std::is_unsigned<uint128_t> : std::true_type {};

/**
 * @brief Adding two string
 * @details Adds two long integer, only used for printing numbers
 * @param first First integer string
 * @param second Second integer string
 * @returns string denoting the addition of both the strings
 */
std::string add(const std::string &first, const std::string &second) {
    std::string third;
    int16_t sum = 0, carry = 0;
    for (int32_t i = static_cast<int32_t>(first.size()) - 1,
                 j = static_cast<int32_t>(second.size()) - 1;
         i >= 0 || j >= 0; --i, --j) {
        sum = ((i >= 0 ? first[i] - '0' : 0) + (j >= 0 ? second[j] - '0' : 0) +
               carry);
        carry = sum / 10;
        sum %= 10;
        third.push_back(sum + '0');
    }
    if (carry) {
        third.push_back('1');
    }
    std::reverse(third.begin(), third.end());
    return third;
}
/**
 * @class uint128_t
 * @brief class for 128-bit unsigned integer
 */
class uint128_t {
    uint64_t f{}, s{};  /// First and second half of 128 bit number

    /**
     * @brief Get integer from given string.
     * @details Create an integer from a given string
     * @param str integer string, can be hexadecimal (starting on 0x... or
     * number)
     * @returns void
     */
    void __get_integer_from_string(const std::string &str) {
        this->f = this->s = 0;
        if (str.size() > 1 && str[1] == 'x') {  // if hexadecimal
            for (auto i = 2; i < str.size(); ++i) {
                *this *= 16LL;
                if (str[i] >= '0' && str[i] <= '9') {
                    *this += (str[i] - '0');
                } else if (str[i] >= 'A' && str[i] <= 'F') {
                    *this += (str[i] - 'A' + 10);
                } else if (str[i] >= 'a' && str[i] <= 'f') {
                    *this += (str[i] - 'a' + 10);
                }
            }
        } else {  // if decimal
            for (auto &x : str) {
                *this *= 10LL;
                *this += (x - '0');
            }
        }
    }

 public:
    uint128_t() = default;

    /**
     * @brief Parameterized constructor
     * @tparam T integral type
     * @param low lower part 8-bit unisgned integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    explicit uint128_t(T low) : s(low) {}

    /**
     * @brief Parameterized constructor
     * @param str Integer string (hexadecimal starting with 0x.. or decimal)
     */
    explicit uint128_t(const std::string &str) {
        __get_integer_from_string(str);
    }

    /**
     * @brief Parameterized constructor
     * @param high higher part 64-bit unsigned integer
     * @param low lower part 64-bit unsigned integer
     */
    uint128_t(const uint64_t high, const uint64_t low) : f(high), s(low) {}

    /**
     * @brief Copy constructor
     * @param num 128-bit unsigned integer
     */
    uint128_t(const uint128_t &num) = default;

    /**
     * @brief Move constructor
     * @param num 128-bit unsigned integer
     */
    uint128_t(uint128_t &&num) noexcept : f(num.f), s(num.s) {}

    /**
     * @brief Destructor for uint128_t
     */
    ~uint128_t() = default;

    /**
     * @brief Leading zeroes in binary
     * @details Calculates leading zeros in 128-bit integer
     * @returns Integer denoting leading zeroes
     */
    inline uint32_t _lez() {
#ifndef _MSC_VER
        if (f) {
            return __builtin_clzll(f);
        }
        return 64 + __builtin_clzll(s);
#else
        unsigned long r = 0;
        _BitScanForward64(&r, f);
        if (r == 64) {
            unsigned long l = 0;
            _BitScanForward64(&l, s);
            return 64 + l;
        }
        return r;
#endif
    }

    /**
     * @brief Trailing zeroes in binary
     * @details Calculates leading zeros in 128-bit integer
     * @returns Integer denoting Trailing zeroes
     */
    inline uint32_t _trz() {
#ifndef _MSC_VER
        if (f) {
            return __builtin_ctzll(f);
        }
        return 64 + __builtin_ctzll(s);
#else
        unsigned long r = 0;
        _BitScanReverse64(&r, s);
        if (r == 64) {
            unsigned long l = 0;
            _BitScanReverse64(&l, f);
            return 64 + l;
        }
        return r;
#endif
    }

    /**
     * @brief casting operator to boolean value
     * @returns true if value of this is non-zero, else false
     */
    inline explicit operator bool() const { return (f || s); }

    /**
     * @brief casting operator to any integer valu
     * @tparam T any integer type
     * @returns integer value casted to mentioned type
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline explicit operator T() const {
        return static_cast<T>(s);
    }

    /**
     * @brief returns lower 64-bit integer part
     * @returns returns lower 64-bit integer part
     */
    inline uint64_t lower() const { return s; }

    /**
     * @brief returns upper 64-bit integer part
     * @returns returns upper 64-bit integer part
     */
    inline uint64_t upper() const { return f; }

    /**
     * @brief operator = for other types
     * @tparam T denoting any integer type
     * @param p an integer to assign it's value
     * @returns this pointer with it's value equal to `p`
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator=(const T &p) {
        this->s = p;
        return *this;
    }

    /**
     * @brief operator = for type string
     * @param p a string to assign it's value to equivalent integer
     * @returns this pointer with it's value equal to `p`
     */
    inline uint128_t &operator=(const std::string &p) {
        this->__get_integer_from_string(p);
        return *this;
    }

    /**
     * @brief operator = for uint128_t
     * @param p an 128-bit integer to assign it's value
     * @returns this pointer with it's value equal to `p`
     */
    inline uint128_t &operator=(const uint128_t &p) = default;

    /**
     * @brief Move assignment operator
     */
    inline uint128_t &operator=(uint128_t &&p) = default;

    /**
     * @brief operator + for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns addition of this and p, returning uint128_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator+(const T p) {
        return uint128_t(f + (p + s < s), p + s);
    }

    /**
     * @brief operator + for uint128_t and other integer types.
     * @param p 128-bit unsigned integer
     * @returns addition of this and p, returning uint128_t integer
     */
    inline uint128_t operator+(const uint128_t &p) {
        return uint128_t(f + (p.s + s < s) + p.f, p.s + s);
    }

    /**
     * @brief operator += for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns addition of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator+=(const T p) {
        bool app = p + s < s;
        this->f += app;
        this->s += p;
        return *this;
    }

    /**
     * @brief operator += for uint128_t
     * @param p 128-bit unsigned integer
     * @returns addition of this and p, returning this
     */
    uint128_t &operator+=(const uint128_t &p) {
        bool app = p.s + s < s;
        f = f + app + p.f;
        s = p.s + s;
        return *this;
    }

    /**
     * @brief pre-increment operator
     * @returns incremented value of this.
     */
    inline uint128_t &operator++() {
        *this += 1;
        return *this;
    }

    /**
     * @brief post-increment operator
     * @returns incremented value of this.
     */
    inline uint128_t operator++(int) {
        ++*this;
        return *this;
    }

    /**
     * @brief operator - for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning uint128_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator-(const T &p) {
        bool app = p > s;
        return uint128_t(f - app, s - p);
    }

    /**
     * @brief operator - for uint128_t
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning uint128_t integer
     */
    inline uint128_t operator-(const uint128_t &p) {
        bool app = p.s > s;
        return uint128_t(f - p.f - app, s - p.s);
    }

    /**
     * @brief operator - using twos complement
     * @returns 2's complement of this.
     */
    inline uint128_t operator-() { return ~*this + uint128_t(1); }

    /**
     * @brief operator -- (pre-decrement)
     * @returns decremented value of this
     */
    inline uint128_t &operator--() {
        *this -= 1;
        return *this;
    }

    /**
     * @brief operator -- (post-decrement)
     * @returns decremented value of this
     */
    inline uint128_t operator--(int p) {
        --*this;
        return *this;
    }

    /**
     * @brief operator -= for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t &operator-=(const T &p) {
        bool app = p > s;
        f -= app;
        s -= p;
        return *this;
    }

    /**
     * @brief operator -= for uint128_t
     * @param p 128-bit unsigned integer
     * @returns subtraction of this and p, returning this
     */
    uint128_t &operator-=(const uint128_t &p) {
        bool app = p.s > s;
        f = f - p.f - app;
        s = s - p.s;
        return *this;
    }

    /**
     * @brief operator * for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns multiplication of this and p, returning uint128_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator*(const T p) {
        return *this * uint128_t(p);
    }

    /**
     * @brief operator * for uint128_t and other integer types.
     * @param p 128-bit unsigned integer
     * @returns multiplication of this and p, returning uint128_t integer
     */
    uint128_t operator*(const uint128_t &p) {
        uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF,
                 s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF;
        uint64_t fi = f_first * s_first, se = f_first * s_second,
                 th = s_first * f_second, fo = s_second * f_second;
        uint64_t tmp = ((se & 0xFFFFFFFF) << 32), tmp2 = (th & 0xFFFFFFFF)
                                                         << 32;
        int cc = (tmp + tmp2 < tmp);
        tmp += tmp2;
        cc += (tmp + fo < tmp);
        uint64_t carry = fi + (se >> 32) + (th >> 32);
        return uint128_t(this->f * p.s + this->s * p.f + carry + cc, tmp + fo);
    }

    /**
     * @brief operator *= for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns multiplication of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator*=(const T p) {
        *this *= uint128_t(p);
        return *this;
    }

    /**
     * @brief operator *= for uint128_t and other integer types.
     * @param p 128-bit unsigned integer
     * @returns multiplication of this and p, returning this
     */
    uint128_t &operator*=(const uint128_t &p) {
        uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF,
                 s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF;
        uint64_t fi = f_first * s_first, se = f_first * s_second,
                 th = s_first * f_second, fo = s_second * f_second;
        uint64_t tmp = (se << 32), tmp2 = (th << 32);
        int cc = (tmp + tmp2 < tmp);
        tmp += tmp2;
        cc += (tmp + fo < tmp);
        uint64_t carry = fi + (se >> 32) + (th >> 32);
        f = this->f * p.s + this->s * p.f + carry + cc;
        s = tmp + fo;
        return *this;
    }

    /**
     * @brief divide function for uint128_t and other integer types.
     * @details divide this value and
     * @param p 128-bit unsigned integer
     * @returns pair denoting quotient and remainder.
     */
    std::pair<uint128_t, uint128_t> divide(const uint128_t &p) {
        if (*this < p) {  // if this is less than divisor
            return {uint128_t(0), *this};
        } else if (*this == p) {  // if this is equal to divisor
            return {uint128_t(1), uint128_t(0)};
        }
        uint128_t tmp = p, tmp2 = *this;
        uint16_t left = tmp._lez() - _lez();
        tmp <<= left;
        uint128_t quotient(0);
        uint128_t zero(0);
        while (tmp2 >= p) {
            uint16_t shf = tmp2._lez() - tmp._lez();
            if (shf) {
                tmp >>= shf;
                quotient <<= shf;
                left -= shf;
            }
            if (tmp2 < tmp) {
                tmp >>= 1;
                quotient <<= 1;
                --left;
            }
            tmp2 -= tmp;
            ++quotient;
        }
        return {quotient << left, tmp2};
    }

    /**
     * @brief operator / for uint128_t and other integer types.
     * @param p 128-bit unsigned integer
     * @returns unsigned 128-bit quotient.
     */
    inline uint128_t operator/(const uint128_t &p) { return divide(p).first; }

    /**
     * @brief operator / for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns unsigned 128-bit quotient.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator/(const T p) {
        uint128_t tmp = *this;
        tmp /= uint128_t(0, p);
        return tmp;
    }

    /**
     * @brief operator /= for uint128_t
     * @param p 128-bit unsigned integer
     * @returns this set as unsigned 128-bit quotient.
     */
    inline uint128_t &operator/=(const uint128_t &p) {
        *this = divide(p).first;
        return *this;
    }

    /**
     * @brief operator /= for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns this set as unsigned 128-bit quotient.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator/=(const T p) {
        *this /= uint128_t(0, p);
        return *this;
    }

    /**
     * @brief operator % for uint128_t
     * @param p 128-bit unsigned integer
     * @returns unsigned 128-bit remainder.
     */
    inline uint128_t operator%(const uint128_t &p) { return divide(p).second; }

    /**
     * @brief operator % for uint128_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns unsigned 128-bit remainder.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator%(const T &p) {
        return *this % uint128_t(p);
    }

    /**
     * @brief operator %= for uint128_t
     * @param p 128-bit unsigned integer
     * @returns this set as unsigned 128-bit remainder.
     */
    inline uint128_t &operator%=(const uint128_t &p) {
        *this = divide(p).second;
        return *this;
    }

    /**
     * @brief operator %= for uint128_t
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns this set as unsigned 128-bit remainder.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator%=(const T &p) {
        *this %= uint128_t(p);
        return *this;
    }

    /**
     * @brief operator < for uint128_t
     * @param other number to be compared with this
     * @returns true if this is less than other, else false
     */
    inline bool operator<(const uint128_t &other) {
        return f < other.f || (f == other.f && s < other.s);
    }

    /**
     * @brief operator <= for uint128_t
     * @param other number to be compared with this
     * @returns true if this is less than or equal to other, else false
     */
    inline bool operator<=(const uint128_t &other) {
        return f < other.f || (f == other.f && s <= other.s);
    }

    /**
     * @brief operator > for uint128_t
     * @param other number to be compared with this
     * @returns true if this is greater than other, else false
     */
    inline bool operator>(const uint128_t &other) {
        return f > other.f || (f == other.f && s > other.s);
    }

    /**
     * @brief operator >= for uint128_t
     * @param other number to be compared with this
     * @returns true if this is greater than or equal than other, else false
     */
    inline bool operator>=(const uint128_t &other) {
        return (f > other.f) || (f == other.f && s >= other.s);
    }

    /**
     * @brief operator == for uint128_t
     * @param other number to be compared with this
     * @returns true if this is equal than other, else false
     */
    inline bool operator==(const uint128_t &other) {
        return f == other.f && s == other.s;
    }

    /**
     * @brief operator != for uint128_t
     * @param other number to be compared with this
     * @returns true if this is not equal than other, else false
     */
    inline bool operator!=(const uint128_t &other) {
        return f != other.f || s != other.s;
    }

    /**
     * @brief operator ! for uint128_t
     * @returns true if this has zero value, else false
     */
    inline bool operator!() { return !f && !s; }

    /**
     * @brief operator && for uint128_t
     * @param b number to be compared with this
     * @returns true if both of the values are not zero, else false
     */
    inline bool operator&&(const uint128_t &b) {
        return (s || f) && (b.s || b.f);
    }

    /**
     * @brief operator || for uint128_t
     * @param b number to be compared with this
     * @returns true if one of the values are not zero, else false
     */
    inline bool operator||(const uint128_t &b) {
        return (s || f) || (b.s || b.f);
    }

    /**
     * @brief operator () for uint128_t
     * @returns true if this value is non-zero, else false
     */
    inline bool operator()() { return s || f; }

    /**
     * @brief operator < for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is less than other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator<(const T other) {
        return *this < uint128_t(other);
    }

    /**
     * @brief operator <= for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is less than or equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator<=(const T other) {
        return *this <= uint128_t(other);
    }

    /**
     * @brief operator > for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is greater than other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator>(const T other) {
        return *this > uint128_t(other);
    }

    /**
     * @brief operator >= for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is greater than or equal other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator>=(const T other) {
        return *this >= uint128_t(other);
    }

    /**
     * @brief operator == for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator==(const T other) {
        return *this == uint128_t(other);
    }

    /**
     * @brief operator != for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is not equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator!=(const T other) {
        return *this != uint128_t(other);
    }

    /**
     * @brief operator && for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is both values are non-zero, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator&&(const T b) {
        return (f || s) && b;
    }

    /**
     * @brief operator || for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is either one of the values are non-zero, else
     * false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator||(const T b) {
        return (f || s) || b;
    }

    /**
     * @brief operator ~ for uint128_t
     * @returns 1's complement of this number
     */
    uint128_t operator~() { return uint128_t(~this->f, ~this->s); }

    /**
     * @brief operator << for uint128_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns value of this shifted by p to left
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t operator<<(const T p) {
        if (!p) {
            return uint128_t(f, s);
        } else if (p >= 64 && p <= 128) {
            return uint128_t((this->s << (p - 64)), 0);
        } else if (p < 64 && p > 0) {
            return uint128_t((this->f << p) + ((this->s >> (64 - p))),
                             this->s << p);
        }
        return uint128_t(0);
    }

    /**
     * @brief operator <<= for uint128_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns this shifted by p to left
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t &operator<<=(const T p) {
        if (p) {
            if (p >= 64 && p <= 128) {
                this->f = (this->s << (p - 64));
                this->s = 0;
            } else {
                f = ((this->f << p) + (this->s >> (64 - p)));
                s = (this->s << p);
            }
        }
        return *this;
    }

    /**
     * @brief operator >> for uint128_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns value of this shifted by p to right
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t operator>>(const T p) {
        if (!p) {
            return uint128_t(this->f, this->s);
        } else if (p >= 64 && p <= 128) {
            return uint128_t(0, (this->f >> (p - 64)));
        } else if (p < 64 && p > 0) {
            return uint128_t((this->f >> p),
                             (this->s >> p) + (this->f << (64 - p)));
        }
        return uint128_t(0);
    }

    /**
     * @brief operator >>= for uint128_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns this shifted by p to right
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t &operator>>=(const T p) {
        if (p) {
            if (p >= 64) {
                f = 0;
                s = (this->f >> (p - 64));
            } else {
                s = (this->s >> p) + (this->f << (64 - p));
                f = (this->f >> p);
            }
        }
        return *this;
    }

    /**
     * @brief operator & for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this & p (& is bit-wise operator)
     */
    inline uint128_t operator&(const uint128_t &p) {
        return uint128_t(this->f & p.f, this->s & p.s);
    }

    /**
     * @brief operator & for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this & p (& is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t operator&(const T p) {
        uint128_t tmp = *this;
        return tmp & uint128_t(p);
    }

    /**
     * @brief operator &= for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this & p (& is bit-wise operator)
     */
    uint128_t &operator&=(const uint128_t &p) {
        this->f &= p.f;
        this->s &= p.s;
        return *this;
    }

    /**
     * @brief operator &= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this & p (& is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint128_t &operator&=(const T p) {
        *this &= uint128_t(p);
        return *this;
    }

    /**
     * @brief operator | for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this | p (| is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator|(const T p) {
        return uint128_t(p | s);
    }

    /**
     * @brief operator | for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this | p (| is bit-wise OR operator)
     */
    inline uint128_t operator|(const uint128_t &p) {
        return uint128_t(this->f | p.f, this->s | p.s);
    }

    /**
     * @brief operator |= for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this | p (| is bit-wise OR operator)
     */
    uint128_t &operator|=(const uint128_t &p) {
        f |= p.f;
        s |= p.s;
        return *this;
    }

    /**
     * @brief operator |= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this | p (| is bit-wise OR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator|=(const T p) {
        s |= p.s;
        return *this;
    }

    /**
     * @brief operator ^ for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this ^ p (^ is bit-wise XOR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t operator^(const T p) {
        return uint128_t(this->f, this->s ^ p);
    }

    /**
     * @brief operator ^ for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this ^ p (^ is bit-wise XOR operator)
     */
    inline uint128_t operator^(const uint128_t &p) {
        return uint128_t(this->f ^ p.f, this->s ^ p.s);
    }

    /**
     * @brief operator ^= for uint128_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this ^ p (^ is bit-wise XOR operator)
     */
    uint128_t &operator^=(const uint128_t &p) {
        f ^= p.f;
        s ^= p.s;
        return *this;
    }

    /**
     * @brief operator ^= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this ^ p (^ is bit-wise XOR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint128_t &operator^=(const T &p) {
        s ^= p;
        return *this;
    }

    /**
     * @brief operator << for printing uint128_t integer
     * @details Prints the uint128_t integer in decimal form
     * @note Note that this operator is costly since it uses strings to print
     * the value
     * @param op ostream object
     * @param p 128-bit integer
     * @returns op, ostream object.
     */
    friend std::ostream &operator<<(std::ostream &op, const uint128_t &p) {
        if (!p.f) {
            op << p.s;
        } else {
            std::string out = "0", p_2 = "1";
            for (int i = 0; i < 64; ++i) {
                if (p.s & (1LL << i)) {
                    out = add(out, p_2);
                }
                p_2 = add(p_2, p_2);
            }
            for (int i = 0; i < 64; ++i) {
                if (p.f & (1LL << i)) {
                    out = add(out, p_2);
                }
                p_2 = add(p_2, p_2);
            }
            op << out;
        }
        return op;
    }
};

// Arithmetic operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator+(const T &p, const uint128_t &q) {
    return uint128_t(p) + q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator-(const T p, const uint128_t &q) {
    return uint128_t(p) - q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator*(const T p, const uint128_t &q) {
    return uint128_t(p) * q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator/(const T p, const uint128_t &q) {
    return uint128_t(p) / q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator%(const T p, const uint128_t &q) {
    return uint128_t(p) % q;
}

// Bitwise operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator&(const T &p, const uint128_t &q) {
    return uint128_t(p) & q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator|(const T p, const uint128_t &q) {
    return uint128_t(p) | q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint128_t operator^(const T p, const uint128_t &q) {
    return uint128_t(p) ^ q;
}

// Boolean operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator&&(const T p, const uint128_t &q) {
    return uint128_t(p) && q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator||(const T p, const uint128_t &q) {
    return uint128_t(p) || q;
}

// Comparison operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator==(const T p, const uint128_t &q) {
    return uint128_t(p) == q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator!=(const T p, const uint128_t &q) {
    return uint128_t(p) != q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator<(const T p, const uint128_t &q) {
    return uint128_t(p) < q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator<=(const T p, const uint128_t &q) {
    return uint128_t(p) <= q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator>(const T p, const uint128_t &q) {
    return uint128_t(p) > q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator>=(const T p, const uint128_t &q) {
    return uint128_t(p) >= q;
}

#endif  // CIPHERS_UINT128_T_HPP_
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.