1163 lines
32 KiB
C++
1163 lines
32 KiB
C++
|
|
/*
|
||
|
|
uint128_t.h
|
||
|
|
An unsigned 128 bit integer type for C++
|
||
|
|
|
||
|
|
Copyright (c) 2013 - 2017 Jason Lee @ calccrypto at gmail.com
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
|
in the Software without restriction, including without limitation the rights
|
||
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
|
copies of the Software, and to permit persons to whom the Software is
|
||
|
|
furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included in
|
||
|
|
all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
|
THE SOFTWARE.
|
||
|
|
|
||
|
|
With much help from Auston Sterling
|
||
|
|
|
||
|
|
Thanks to Stefan Deigmüller for finding
|
||
|
|
a bug in operator*.
|
||
|
|
|
||
|
|
Thanks to François Dessenne for convincing me
|
||
|
|
to do a general rewrite of this class.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef __UINT128_T__
|
||
|
|
#define __UINT128_T__
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <cctype>
|
||
|
|
#include <sstream>
|
||
|
|
|
||
|
|
#include <cstdint>
|
||
|
|
#include <ostream>
|
||
|
|
#include <stdexcept>
|
||
|
|
#include <string>
|
||
|
|
#include <type_traits>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "endianness.h"
|
||
|
|
|
||
|
|
class uint128_t
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
#ifdef __BIG_ENDIAN__
|
||
|
|
uint64_t UPPER, LOWER;
|
||
|
|
#endif
|
||
|
|
#ifdef __LITTLE_ENDIAN__
|
||
|
|
uint64_t LOWER, UPPER;
|
||
|
|
#endif
|
||
|
|
public:
|
||
|
|
// Constructors
|
||
|
|
constexpr uint128_t() : LOWER{0}, UPPER{0} {}
|
||
|
|
constexpr uint128_t(const uint128_t & rhs) = default;
|
||
|
|
constexpr uint128_t(uint128_t && rhs) = default;
|
||
|
|
|
||
|
|
// do not use prefixes (0x, 0b, etc.)
|
||
|
|
// if the input string is too long, only right most characters are read
|
||
|
|
uint128_t(const std::string & s, uint8_t base)
|
||
|
|
: LOWER{}, UPPER{}
|
||
|
|
{
|
||
|
|
init(s.c_str(), s.size(), base);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint128_t(const char *s, const std::size_t len, uint8_t base)
|
||
|
|
: LOWER{}, UPPER{}
|
||
|
|
{
|
||
|
|
init(s, len, base);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t(const bool & b)
|
||
|
|
: uint128_t((uint8_t) b)
|
||
|
|
{}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t(const T & rhs)
|
||
|
|
#ifdef __BIG_ENDIAN__
|
||
|
|
: UPPER(0), LOWER(rhs)
|
||
|
|
#endif
|
||
|
|
#ifdef __LITTLE_ENDIAN__
|
||
|
|
: LOWER(rhs), UPPER(0)
|
||
|
|
#endif
|
||
|
|
{
|
||
|
|
if (std::is_signed<T>::value) {
|
||
|
|
if (rhs < 0) {
|
||
|
|
UPPER = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename S, typename T, typename = typename std::enable_if <std::is_integral<S>::value && std::is_integral<T>::value, void>::type>
|
||
|
|
constexpr uint128_t(const S & upper_rhs, const T & lower_rhs)
|
||
|
|
#ifdef __BIG_ENDIAN__
|
||
|
|
: UPPER(upper_rhs), LOWER(lower_rhs)
|
||
|
|
#endif
|
||
|
|
#ifdef __LITTLE_ENDIAN__
|
||
|
|
: LOWER(lower_rhs), UPPER(upper_rhs)
|
||
|
|
#endif
|
||
|
|
{}
|
||
|
|
|
||
|
|
// Assignment Operator
|
||
|
|
constexpr uint128_t & operator=(const uint128_t & rhs) = default;
|
||
|
|
constexpr uint128_t & operator=(uint128_t && rhs) = default;
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator=(const T & rhs)
|
||
|
|
{
|
||
|
|
UPPER = 0;
|
||
|
|
|
||
|
|
if (std::is_signed<T>::value) {
|
||
|
|
if (rhs < 0) {
|
||
|
|
UPPER = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
LOWER = rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator=(const bool & rhs)
|
||
|
|
{
|
||
|
|
UPPER = 0;
|
||
|
|
LOWER = rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Typecast Operators
|
||
|
|
constexpr operator bool() const
|
||
|
|
{
|
||
|
|
return static_cast<bool>(UPPER | LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr operator uint8_t() const
|
||
|
|
{
|
||
|
|
return static_cast<uint8_t>(LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr operator uint16_t() const
|
||
|
|
{
|
||
|
|
return static_cast<uint16_t>(LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr operator uint32_t() const
|
||
|
|
{
|
||
|
|
return static_cast<uint32_t>(LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr operator uint64_t() const
|
||
|
|
{
|
||
|
|
return static_cast<uint64_t>(LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Bitwise Operators
|
||
|
|
constexpr uint128_t operator&(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator&(const T & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(0, LOWER & (uint64_t) rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator&=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
UPPER &= rhs.UPPER;
|
||
|
|
LOWER &= rhs.LOWER;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator&=(const T & rhs){
|
||
|
|
UPPER = 0;
|
||
|
|
LOWER &= rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator|(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator|(const T & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER, LOWER | (uint64_t) rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator|=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
UPPER |= rhs.UPPER;
|
||
|
|
LOWER |= rhs.LOWER;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator|=(const T & rhs)
|
||
|
|
{
|
||
|
|
LOWER |= (uint64_t) rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator^(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator^(const T & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER, LOWER ^ (uint64_t) rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator^=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
UPPER ^= rhs.UPPER;
|
||
|
|
LOWER ^= rhs.LOWER;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator^=(const T & rhs)
|
||
|
|
{
|
||
|
|
LOWER ^= (uint64_t) rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator~() const
|
||
|
|
{
|
||
|
|
return uint128_t(~UPPER, ~LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Bit Shift Operators
|
||
|
|
constexpr uint128_t operator<<(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
const uint64_t shift = rhs.LOWER;
|
||
|
|
if (static_cast<bool>(rhs.UPPER) || (shift >= 128))
|
||
|
|
{
|
||
|
|
return uint128_t{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, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator<<(const T & rhs) const
|
||
|
|
{
|
||
|
|
return *this << uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator<<=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this << rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
const uint64_t shift = rhs.LOWER;
|
||
|
|
if (static_cast<bool>(rhs.UPPER) || (shift >= 128))
|
||
|
|
{
|
||
|
|
return uint128_t{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};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator>>(const T & rhs) const
|
||
|
|
{
|
||
|
|
return *this >> uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator>>=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this >> rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator>>=(const T & rhs)
|
||
|
|
{
|
||
|
|
*this = *this >> uint128_t(rhs);
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Logical Operators
|
||
|
|
constexpr bool operator!() const
|
||
|
|
{
|
||
|
|
return !static_cast<bool>(UPPER | LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator&&(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return static_cast<bool>(*this && rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator||(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return static_cast<bool>(*this || rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator&&(const T & rhs) const
|
||
|
|
{
|
||
|
|
return static_cast<bool>(*this && rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator||(const T & rhs) const
|
||
|
|
{
|
||
|
|
return static_cast<bool>(*this || rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator==(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator==(const T & rhs) const
|
||
|
|
{
|
||
|
|
return (!UPPER && (LOWER == (uint64_t) rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator!=(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator!=(const T & rhs) const
|
||
|
|
{
|
||
|
|
return (UPPER | (LOWER != (uint64_t) rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator>(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
if (UPPER == rhs.UPPER)
|
||
|
|
{
|
||
|
|
return (LOWER > rhs.LOWER);
|
||
|
|
}
|
||
|
|
return (UPPER > rhs.UPPER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator>(const T & rhs) const
|
||
|
|
{
|
||
|
|
return (UPPER || (LOWER > (uint64_t) rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator<(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
if (UPPER == rhs.UPPER)
|
||
|
|
{
|
||
|
|
return (LOWER < rhs.LOWER);
|
||
|
|
}
|
||
|
|
return (UPPER < rhs.UPPER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator<(const T & rhs) const
|
||
|
|
{
|
||
|
|
return (!UPPER)?(LOWER < (uint64_t) rhs):false;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator>=(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return ((*this > rhs) | (*this == rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator>=(const T & rhs) const
|
||
|
|
{
|
||
|
|
return ((*this > rhs) | (*this == rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr bool operator<=(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return ((*this < rhs) | (*this == rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator<=(const T & rhs) const
|
||
|
|
{
|
||
|
|
return ((*this < rhs) | (*this == rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Arithmetic Operators
|
||
|
|
constexpr uint128_t operator+(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER + rhs.UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator+(const T & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator+=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
UPPER += rhs.UPPER + ((LOWER + rhs.LOWER) < LOWER);
|
||
|
|
LOWER += rhs.LOWER;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator+=(const T & rhs)
|
||
|
|
{
|
||
|
|
return *this += uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator-(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator-(const T & rhs) const
|
||
|
|
{
|
||
|
|
return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator-=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this - rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator-=(const T & rhs)
|
||
|
|
{
|
||
|
|
return *this = *this - uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator*(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
// split values into 4 32-bit parts
|
||
|
|
uint64_t top[4] = {UPPER >> 32, UPPER & 0xffffffff, LOWER >> 32, LOWER & 0xffffffff};
|
||
|
|
uint64_t bottom[4] = {rhs.UPPER >> 32, rhs.UPPER & 0xffffffff, rhs.LOWER >> 32, rhs.LOWER & 0xffffffff};
|
||
|
|
uint64_t products[4][4]{};
|
||
|
|
|
||
|
|
// multiply each component of the values
|
||
|
|
for (int y = 3; y > -1; y--)
|
||
|
|
{
|
||
|
|
for (int x = 3; x > -1; x--)
|
||
|
|
{
|
||
|
|
products[3 - x][y] = top[x] * bottom[y];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// first row
|
||
|
|
uint64_t fourth32 = (products[0][3] & 0xffffffff);
|
||
|
|
uint64_t third32 = (products[0][2] & 0xffffffff) + (products[0][3] >> 32);
|
||
|
|
uint64_t second32 = (products[0][1] & 0xffffffff) + (products[0][2] >> 32);
|
||
|
|
uint64_t first32 = (products[0][0] & 0xffffffff) + (products[0][1] >> 32);
|
||
|
|
|
||
|
|
// second row
|
||
|
|
third32 += (products[1][3] & 0xffffffff);
|
||
|
|
second32 += (products[1][2] & 0xffffffff) + (products[1][3] >> 32);
|
||
|
|
first32 += (products[1][1] & 0xffffffff) + (products[1][2] >> 32);
|
||
|
|
|
||
|
|
// third row
|
||
|
|
second32 += (products[2][3] & 0xffffffff);
|
||
|
|
first32 += (products[2][2] & 0xffffffff) + (products[2][3] >> 32);
|
||
|
|
|
||
|
|
// fourth row
|
||
|
|
first32 += (products[3][3] & 0xffffffff);
|
||
|
|
|
||
|
|
// move carry to next digit
|
||
|
|
third32 += fourth32 >> 32;
|
||
|
|
second32 += third32 >> 32;
|
||
|
|
first32 += second32 >> 32;
|
||
|
|
|
||
|
|
// remove carry from current digit
|
||
|
|
fourth32 &= 0xffffffff;
|
||
|
|
third32 &= 0xffffffff;
|
||
|
|
second32 &= 0xffffffff;
|
||
|
|
first32 &= 0xffffffff;
|
||
|
|
|
||
|
|
// combine components
|
||
|
|
return uint128_t((first32 << 32) | second32, (third32 << 32) | fourth32);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator*(const T & rhs) const
|
||
|
|
{
|
||
|
|
return *this * uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator*=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this * rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator*=(const T & rhs)
|
||
|
|
{
|
||
|
|
return *this = *this * uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
void export_bits(std::vector<uint8_t> & ret) const
|
||
|
|
{
|
||
|
|
ConvertToVector(ret, const_cast<const uint64_t&>(UPPER));
|
||
|
|
ConvertToVector(ret, const_cast<const uint64_t&>(LOWER));
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
constexpr std::pair<uint128_t, uint128_t> divmod(const uint128_t & lhs, const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
// Save some calculations /////////////////////
|
||
|
|
if (rhs == uint128_t{0})
|
||
|
|
{
|
||
|
|
throw std::domain_error("Error: division or modulus by 0");
|
||
|
|
}
|
||
|
|
else if (rhs == uint128_t{1})
|
||
|
|
{
|
||
|
|
return std::pair <uint128_t, uint128_t> (lhs, uint128_t{0});
|
||
|
|
}
|
||
|
|
else if (lhs == rhs)
|
||
|
|
{
|
||
|
|
return std::pair <uint128_t, uint128_t> (uint128_t{1}, uint128_t{0});
|
||
|
|
}
|
||
|
|
else if ((lhs == uint128_t{0}) || (lhs < rhs))
|
||
|
|
{
|
||
|
|
return std::pair <uint128_t, uint128_t> (uint128_t{0}, lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::pair<uint128_t, uint128_t> qr(uint128_t{0}, uint128_t{0});
|
||
|
|
for (uint8_t x = lhs.bits(); x > 0; x--)
|
||
|
|
{
|
||
|
|
qr.first <<= uint128_t{1};
|
||
|
|
qr.second <<= uint128_t{1};
|
||
|
|
|
||
|
|
if ((lhs >> (x - 1U)) & 1)
|
||
|
|
{
|
||
|
|
++qr.second;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (qr.second >= rhs)
|
||
|
|
{
|
||
|
|
qr.second -= rhs;
|
||
|
|
++qr.first;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return qr;
|
||
|
|
}
|
||
|
|
void ConvertToVector(std::vector<uint8_t> & ret, const uint64_t & val) const
|
||
|
|
{
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 56));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 48));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 40));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 32));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 24));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 16));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val >> 8));
|
||
|
|
ret.push_back(static_cast<uint8_t>(val));
|
||
|
|
}
|
||
|
|
|
||
|
|
// do not use prefixes (0x, 0b, etc.)
|
||
|
|
// if the input string is too long, only right most characters are read
|
||
|
|
void init(const char *s, std::size_t len, uint8_t base)
|
||
|
|
{
|
||
|
|
if ((s == NULL) || !len || (s[0] == '\x00'))
|
||
|
|
{
|
||
|
|
LOWER = UPPER = 0;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (*s && len && std::isspace(*s))
|
||
|
|
{
|
||
|
|
++s;
|
||
|
|
len--;
|
||
|
|
}
|
||
|
|
|
||
|
|
// no prefixes
|
||
|
|
switch (base)
|
||
|
|
{
|
||
|
|
case 16:
|
||
|
|
_init_hex(s, len);
|
||
|
|
break;
|
||
|
|
case 10:
|
||
|
|
_init_dec(s, len);
|
||
|
|
break;
|
||
|
|
case 8:
|
||
|
|
_init_oct(s, len);
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
_init_bin(s, len);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
// should probably throw error here
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void _init_hex(const char *s, std::size_t len)
|
||
|
|
{
|
||
|
|
// 2**128 = 0x100000000000000000000000000000000.
|
||
|
|
static const std::size_t MAX_LEN = 32;
|
||
|
|
|
||
|
|
LOWER = UPPER = 0;
|
||
|
|
if (!s || !len)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const std::size_t max_len = std::min(len, MAX_LEN);
|
||
|
|
const std::size_t starting_index = (MAX_LEN < len)?(len - MAX_LEN):0;
|
||
|
|
const std::size_t double_lower = sizeof(LOWER) * 2;
|
||
|
|
const std::size_t lower_len = (max_len >= double_lower)?double_lower:max_len;
|
||
|
|
const std::size_t upper_len = (max_len >= double_lower)?(max_len - double_lower):0;
|
||
|
|
|
||
|
|
std::stringstream lower_s, upper_s;
|
||
|
|
upper_s << std::hex << std::string(s + starting_index, upper_len);
|
||
|
|
lower_s << std::hex << std::string(s + starting_index + upper_len, lower_len);
|
||
|
|
|
||
|
|
// should check for errors
|
||
|
|
upper_s >> UPPER;
|
||
|
|
lower_s >> LOWER;
|
||
|
|
}
|
||
|
|
|
||
|
|
void _init_dec(const char *s, std::size_t len)
|
||
|
|
{
|
||
|
|
// 2**128 = 340282366920938463463374607431768211456.
|
||
|
|
static const std::size_t MAX_LEN = 39;
|
||
|
|
|
||
|
|
LOWER = UPPER = 0;
|
||
|
|
if (!s || !len)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const std::size_t max_len = std::min(len, MAX_LEN);
|
||
|
|
const std::size_t starting_index = (MAX_LEN < len)?(len - MAX_LEN):0;
|
||
|
|
s += starting_index;
|
||
|
|
|
||
|
|
for (std::size_t i = 0; *s && ('0' <= *s) && (*s <= '9') && (i < max_len); ++s, ++i)
|
||
|
|
{
|
||
|
|
*this *= 10;
|
||
|
|
*this += *s - '0';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void _init_oct(const char *s, std::size_t len)
|
||
|
|
{
|
||
|
|
// 2**128 = 0o4000000000000000000000000000000000000000000.
|
||
|
|
static const std::size_t MAX_LEN = 43;
|
||
|
|
|
||
|
|
LOWER = UPPER = 0;
|
||
|
|
if (!s || !len)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const std::size_t max_len = std::min(len, MAX_LEN);
|
||
|
|
const std::size_t starting_index = (MAX_LEN < len)?(len - MAX_LEN):0;
|
||
|
|
s += starting_index;
|
||
|
|
|
||
|
|
for (std::size_t i = 0; *s && ('0' <= *s) && (*s <= '7') && (i < max_len); ++s, ++i)
|
||
|
|
{
|
||
|
|
*this *= 8;
|
||
|
|
*this += *s - '0';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void _init_bin(const char *s, std::size_t len)
|
||
|
|
{
|
||
|
|
// 2**128 = 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
|
||
|
|
static const std::size_t MAX_LEN = 128;
|
||
|
|
|
||
|
|
LOWER = UPPER = 0;
|
||
|
|
if (!s || !len)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const std::size_t max_len = std::min(len, MAX_LEN);
|
||
|
|
const std::size_t starting_index = (MAX_LEN < len)?(len - MAX_LEN):0;
|
||
|
|
const std::size_t eight_lower = sizeof(LOWER) * 8;
|
||
|
|
const std::size_t lower_len = (max_len >= eight_lower)?eight_lower:max_len;
|
||
|
|
const std::size_t upper_len = (max_len >= eight_lower)?(max_len - eight_lower):0;
|
||
|
|
s += starting_index;
|
||
|
|
|
||
|
|
for (std::size_t i = 0; *s && ('0' <= *s) && (*s <= '1') && (i < upper_len); ++s, ++i)
|
||
|
|
{
|
||
|
|
UPPER <<= 1;
|
||
|
|
UPPER |= *s - '0';
|
||
|
|
}
|
||
|
|
|
||
|
|
for (std::size_t i = 0; *s && ('0' <= *s) && (*s <= '1') && (i < lower_len); ++s, ++i)
|
||
|
|
{
|
||
|
|
LOWER <<= 1;
|
||
|
|
LOWER |= *s - '0';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
constexpr uint128_t operator/(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return divmod(*this, rhs).first;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator/(const T & rhs) const
|
||
|
|
{
|
||
|
|
return *this / uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator/=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this / rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator/=(const T & rhs)
|
||
|
|
{
|
||
|
|
return *this = *this / uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator%(const uint128_t & rhs) const
|
||
|
|
{
|
||
|
|
return divmod(*this, rhs).second;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator%(const T & rhs) const
|
||
|
|
{
|
||
|
|
return *this % uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t & operator%=(const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
*this = *this % rhs;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t & operator%=(const T & rhs)
|
||
|
|
{
|
||
|
|
return *this = *this % uint128_t(rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Increment Operator
|
||
|
|
constexpr uint128_t & operator++()
|
||
|
|
{
|
||
|
|
return *this += uint128_t{1};
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator++(int)
|
||
|
|
{
|
||
|
|
uint128_t temp(*this);
|
||
|
|
++*this;
|
||
|
|
return temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Decrement Operator
|
||
|
|
constexpr uint128_t & operator--()
|
||
|
|
{
|
||
|
|
return *this -= uint128_t{1};
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator--(int)
|
||
|
|
{
|
||
|
|
uint128_t temp(*this);
|
||
|
|
--*this;
|
||
|
|
return temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Nothing done since promotion doesn't work here
|
||
|
|
constexpr uint128_t operator+() const
|
||
|
|
{
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// two's complement
|
||
|
|
constexpr uint128_t operator-() const
|
||
|
|
{
|
||
|
|
return ~*this + uint128_t{1};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get private values
|
||
|
|
constexpr const uint64_t & upper() const
|
||
|
|
{
|
||
|
|
return UPPER;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr const uint64_t & lower() const
|
||
|
|
{
|
||
|
|
return LOWER;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get bitsize of value
|
||
|
|
constexpr uint8_t bits() const
|
||
|
|
{
|
||
|
|
uint8_t out = 0;
|
||
|
|
if (UPPER)
|
||
|
|
{
|
||
|
|
out = 64;
|
||
|
|
uint64_t up = UPPER;
|
||
|
|
while (up)
|
||
|
|
{
|
||
|
|
up >>= 1;
|
||
|
|
out++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
uint64_t low = LOWER;
|
||
|
|
while (low)
|
||
|
|
{
|
||
|
|
low >>= 1;
|
||
|
|
out++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get string representation of value
|
||
|
|
std::string str(uint8_t base = 10, const unsigned int & len = 0) const
|
||
|
|
{
|
||
|
|
if ((base < 2) || (base > 16))
|
||
|
|
{
|
||
|
|
throw std::invalid_argument("Base must be in the range [2, 16]");
|
||
|
|
}
|
||
|
|
std::string out = "";
|
||
|
|
if (!(*this))
|
||
|
|
{
|
||
|
|
out = "0";
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
std::pair <uint128_t, uint128_t> qr(*this, uint128_t{0});
|
||
|
|
do{
|
||
|
|
qr = divmod(qr.first, base);
|
||
|
|
out = "0123456789abcdef"[(uint8_t) qr.second] + out;
|
||
|
|
} while (qr.first);
|
||
|
|
}
|
||
|
|
if (out.size() < len)
|
||
|
|
{
|
||
|
|
out = std::string(len - out.size(), '0') + out;
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
}; // class uint256_t
|
||
|
|
|
||
|
|
// lhs type T as first arguemnt
|
||
|
|
// If the output is not a bool, casts to type T
|
||
|
|
|
||
|
|
// Bitwise Operators
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator&(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return rhs & lhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator&=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (rhs & lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator|(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return rhs | lhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator|=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (rhs | lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator^(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return rhs ^ lhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator^=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (rhs ^ lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const bool & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const uint8_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const uint16_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const uint32_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const uint64_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const int8_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const int16_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const int32_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator<<(const int64_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) << rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator<<=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (uint128_t(lhs) << rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const bool & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const uint8_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const uint16_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const uint32_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const uint64_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const int8_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const int16_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const int32_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
constexpr uint128_t operator>>(const int64_t & lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) >> rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator>>=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (uint128_t(lhs) >> rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Comparison Operators
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator==(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return (!rhs.upper() && ((uint64_t) lhs == rhs.lower()));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator!=(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return (rhs.upper() | ((uint64_t) lhs != rhs.lower()));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator>(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return (!rhs.upper()) && ((uint64_t) lhs > rhs.lower());
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator<(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
if (rhs.upper())
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return ((uint64_t) lhs < rhs.lower());
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator>=(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
if (rhs.upper())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return ((uint64_t) lhs >= rhs.lower());
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr bool operator<=(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
if (rhs.upper())
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return ((uint64_t) lhs <= rhs.lower());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Arithmetic Operators
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator+(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return rhs + lhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator+=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (rhs + lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator-(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return -(rhs - lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator-=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (-(rhs - lhs));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator*(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return rhs * lhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator*=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (rhs * lhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator/(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) / rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator/=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (uint128_t(lhs) / rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr uint128_t operator%(const T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return uint128_t(lhs) % rhs;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type >
|
||
|
|
constexpr T & operator%=(T &lhs, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
return lhs = static_cast <T> (uint128_t(lhs) % rhs);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::ostream & operator<<(std::ostream & stream, const uint128_t & rhs)
|
||
|
|
{
|
||
|
|
if (stream.flags() & stream.oct)
|
||
|
|
{
|
||
|
|
stream << rhs.str(8);
|
||
|
|
}
|
||
|
|
else if (stream.flags() & stream.dec)
|
||
|
|
{
|
||
|
|
stream << rhs.str(10);
|
||
|
|
}
|
||
|
|
else if (stream.flags() & stream.hex)
|
||
|
|
{
|
||
|
|
stream << rhs.str(16);
|
||
|
|
}
|
||
|
|
return stream;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|