adding uint128 type
This commit is contained in:
parent
382f741c73
commit
29a1346d05
3 changed files with 362 additions and 0 deletions
|
|
@ -58,6 +58,7 @@ include_directories( ${OPENSSL_INCLUDE_DIR} )
|
|||
SET( ALL_OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE})
|
||||
|
||||
set( fc_sources
|
||||
src/uint128.cpp
|
||||
src/variant.cpp
|
||||
src/exception.cpp
|
||||
src/variant_object.cpp
|
||||
|
|
|
|||
91
include/fc/uint128.hpp
Normal file
91
include/fc/uint128.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
/**
|
||||
* @brief an implementation of 128 bit unsigned integer
|
||||
*
|
||||
*/
|
||||
class uint128
|
||||
{
|
||||
private:
|
||||
uint128( uint64_t _h, uint64_t _l )
|
||||
:hi(_h),lo(_l){}
|
||||
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
|
||||
public:
|
||||
uint128():hi(0),lo(0){};
|
||||
uint128( uint32_t l ):hi(0),lo(l){}
|
||||
uint128( int32_t l ):hi( -(l<0) ),lo(l){}
|
||||
uint128( int64_t l ):hi( -(l<0) ),lo(l){}
|
||||
uint128( uint64_t l ):hi(0),lo(l){}
|
||||
uint128( const std::string& s );
|
||||
|
||||
operator std::string()const;
|
||||
|
||||
bool operator == ( const uint128& o )const{ return hi == o.hi && lo == o.lo; }
|
||||
bool operator != ( const uint128& o )const{ return hi != o.hi || lo != o.lo; }
|
||||
bool operator < ( const uint128& o )const { return (hi == o.hi) ? lo < o.lo : hi < o.hi; }
|
||||
bool operator !()const { return !(hi !=0 || lo != 0); }
|
||||
uint128 operator -()const { return ++uint128( ~hi, ~lo ); }
|
||||
|
||||
uint128& operator++() { hi += (++lo == 0); return *this; }
|
||||
uint128& operator--() { hi -= (lo-- == 0); return *this; }
|
||||
uint128 operator++(int) { auto tmp = *this; ++(*this); return tmp; }
|
||||
uint128 operator--(int) { auto tmp = *this; --(*this); return tmp; }
|
||||
|
||||
uint128& operator |= ( const uint128& u ) { hi |= u.hi; lo |= u.lo; return *this; }
|
||||
uint128& operator &= ( const uint128& u ) { hi &= u.hi; lo &= u.lo; return *this; }
|
||||
uint128& operator ^= ( const uint128& u ) { hi ^= u.hi; lo ^= u.lo; return *this; }
|
||||
uint128& operator <<= ( const uint128& u );
|
||||
uint128& operator >>= ( const uint128& u );
|
||||
|
||||
uint128& operator += ( const uint128& u ) { const uint64_t old = lo; lo += u.lo; hi += u.hi + (lo < old); return *this; }
|
||||
uint128& operator -= ( const uint128& u ) { return *this += -u; }
|
||||
uint128& operator *= ( const uint128& u );
|
||||
uint128& operator /= ( const uint128& u );
|
||||
uint128& operator %= ( const uint128& u );
|
||||
|
||||
|
||||
friend uint128 operator + ( const uint128& l, const uint128& r ) { return uint128(l)+=r; }
|
||||
friend uint128 operator - ( const uint128& l, const uint128& r ) { return uint128(l)-=r; }
|
||||
friend uint128 operator * ( const uint128& l, const uint128& r ) { return uint128(l)*=r; }
|
||||
friend uint128 operator / ( const uint128& l, const uint128& r ) { return uint128(l)/=r; }
|
||||
friend uint128 operator | ( const uint128& l, const uint128& r ) { return uint128(l)=(r); }
|
||||
friend uint128 operator & ( const uint128& l, const uint128& r ) { return uint128(l)&=r; }
|
||||
friend uint128 operator ^ ( const uint128& l, const uint128& r ) { return uint128(l)^=r; }
|
||||
friend uint128 operator << ( const uint128& l, const uint128& r ) { return uint128(l)<<=r; }
|
||||
friend uint128 operator >> ( const uint128& l, const uint128& r ) { return uint128(l)>>=r; }
|
||||
friend bool operator > ( const uint128& l, const uint128& r ) { return r < l; }
|
||||
|
||||
uint128 operator ~()const { return uint128( ~hi, ~lo ); }
|
||||
// uint128& operator ~=( const uint128& u );// { /*hi ~= u.hi; lo ~= u.lo;*/ return *this; }
|
||||
|
||||
friend bool operator >= ( const uint128& l, const uint128& r ) { return l == r || l > r; }
|
||||
friend bool operator <= ( const uint128& l, const uint128& r ) { return l == r || l < r; }
|
||||
|
||||
uint32_t to_integer()const { return lo; }
|
||||
|
||||
};
|
||||
static_assert( sizeof(uint128) == 2*sizeof(uint64_t), "validate packing assumptions" );
|
||||
|
||||
typedef uint128 uint128_t;
|
||||
|
||||
class variant;
|
||||
|
||||
void to_variant( const uint128& var, variant& vo );
|
||||
void from_variant( const variant& var, uint128& vo );
|
||||
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const uint128& u ) { s.write( (char*)&u, sizeof(u) ); }
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, uint128& u ) { s.read( (char*)&u, sizeof(u) ); }
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
270
src/uint128.cpp
Normal file
270
src/uint128.cpp
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
#include <fc/uint128.hpp>
|
||||
#include <fc/variant.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
template <typename T>
|
||||
static void divide(const T &numerator, const T &denominator, T "ient, T &remainder)
|
||||
{
|
||||
|
||||
static const int bits = sizeof(T) * 8;//CHAR_BIT;
|
||||
|
||||
if(denominator == 0) {
|
||||
throw std::domain_error("divide by zero");
|
||||
} else {
|
||||
T n = numerator;
|
||||
T d = denominator;
|
||||
T x = 1;
|
||||
T answer = 0;
|
||||
|
||||
|
||||
while((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
|
||||
x <<= 1;
|
||||
d <<= 1;
|
||||
}
|
||||
|
||||
while(x != 0) {
|
||||
if(n >= d) {
|
||||
n -= d;
|
||||
answer |= x;
|
||||
}
|
||||
|
||||
x >>= 1;
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
quotient = answer;
|
||||
remainder = n;
|
||||
}
|
||||
}
|
||||
|
||||
uint128::uint128(const std::string &sz)
|
||||
:hi(0), lo(0)
|
||||
{
|
||||
// do we have at least one character?
|
||||
if(!sz.empty()) {
|
||||
// make some reasonable assumptions
|
||||
int radix = 10;
|
||||
bool minus = false;
|
||||
|
||||
std::string::const_iterator i = sz.begin();
|
||||
|
||||
// check for minus sign, i suppose technically this should only apply
|
||||
// to base 10, but who says that -0x1 should be invalid?
|
||||
if(*i == '-') {
|
||||
++i;
|
||||
minus = true;
|
||||
}
|
||||
|
||||
// check if there is radix changing prefix (0 or 0x)
|
||||
if(i != sz.end()) {
|
||||
if(*i == '0') {
|
||||
radix = 8;
|
||||
++i;
|
||||
if(i != sz.end()) {
|
||||
if(*i == 'x') {
|
||||
radix = 16;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(i != sz.end()) {
|
||||
unsigned int n;
|
||||
const char ch = *i;
|
||||
|
||||
if(ch >= 'A' && ch <= 'Z') {
|
||||
if(((ch - 'A') + 10) < radix) {
|
||||
n = (ch - 'A') + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if(ch >= 'a' && ch <= 'z') {
|
||||
if(((ch - 'a') + 10) < radix) {
|
||||
n = (ch - 'a') + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if(ch >= '0' && ch <= '9') {
|
||||
if((ch - '0') < radix) {
|
||||
n = (ch - '0');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* completely invalid character */
|
||||
break;
|
||||
}
|
||||
|
||||
(*this) *= radix;
|
||||
(*this) += n;
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// if this was a negative number, do that two's compliment madness :-P
|
||||
if(minus) {
|
||||
*this = -*this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint128::operator std::string ()const
|
||||
{
|
||||
if(*this == 0) { return "0"; }
|
||||
|
||||
// at worst it will be size digits (base 2) so make our buffer
|
||||
// that plus room for null terminator
|
||||
static char sz [128 + 1];
|
||||
sz[sizeof(sz) - 1] = '\0';
|
||||
|
||||
uint128 ii(*this);
|
||||
int i = 128 - 1;
|
||||
|
||||
while (ii != 0 && i) {
|
||||
|
||||
uint128 remainder;
|
||||
divide(ii, uint128(10), ii, remainder);
|
||||
sz [--i] = "0123456789abcdefghijklmnopqrstuvwxyz"[remainder.to_integer()];
|
||||
}
|
||||
|
||||
return &sz[i];
|
||||
}
|
||||
|
||||
|
||||
uint128& uint128::operator<<=(const uint128& rhs)
|
||||
{
|
||||
unsigned int n = rhs.to_integer();
|
||||
|
||||
if(n >= 128)
|
||||
{
|
||||
hi = 0;
|
||||
lo = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned int halfsize = 128 / 2;
|
||||
|
||||
if(n >= halfsize){
|
||||
n -= halfsize;
|
||||
hi = lo;
|
||||
lo = 0;
|
||||
}
|
||||
|
||||
if(n != 0) {
|
||||
// shift high half
|
||||
hi <<= n;
|
||||
|
||||
const uint64_t mask(~(uint64_t(-1) >> n));
|
||||
|
||||
// and add them to high half
|
||||
hi |= (lo & mask) >> (halfsize - n);
|
||||
|
||||
// and finally shift also low half
|
||||
lo <<= n;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128 & uint128::operator>>=(const uint128& rhs)
|
||||
{
|
||||
unsigned int n = rhs.to_integer();
|
||||
|
||||
if(n >= 128) {
|
||||
hi = 0;
|
||||
lo = 0;
|
||||
} else {
|
||||
const unsigned int halfsize = 128 / 2;
|
||||
|
||||
if(n >= halfsize) {
|
||||
n -= halfsize;
|
||||
lo = hi;
|
||||
hi = 0;
|
||||
}
|
||||
|
||||
if(n != 0) {
|
||||
// shift low half
|
||||
lo >>= n;
|
||||
|
||||
// get lower N bits of high half
|
||||
const uint64_t mask(~(uint64_t(-1) << n));
|
||||
|
||||
// and add them to low qword
|
||||
lo |= (hi & mask) << (halfsize - n);
|
||||
|
||||
// and finally shift also high half
|
||||
hi >>= n;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator/=(const uint128 &b)
|
||||
{
|
||||
uint128 remainder;
|
||||
divide(*this, b, *this, remainder);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator%=(const uint128 &b)
|
||||
{
|
||||
uint128 quotient;
|
||||
divide(*this, b, quotient, *this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint128& uint128::operator*=(const uint128 &b)
|
||||
{
|
||||
// check for multiply by 0
|
||||
// result is always 0 :-P
|
||||
if(b == 0) {
|
||||
hi = 0;
|
||||
lo = 0;
|
||||
} else if(b != 1) {
|
||||
|
||||
// check we aren't multiplying by 1
|
||||
|
||||
uint128 a(*this);
|
||||
uint128 t = b;
|
||||
|
||||
lo = 0;
|
||||
hi = 0;
|
||||
|
||||
for (unsigned int i = 0; i < 128; ++i) {
|
||||
if((t & 1) != 0) {
|
||||
*this += (a << i);
|
||||
}
|
||||
|
||||
t >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
void to_variant( const uint128& var, variant& vo ) { vo = std::string(var); }
|
||||
void from_variant( const variant& var, uint128& vo ){ vo = uint128(var.as_string()); }
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
/*
|
||||
* Portions of the above code were adapted from the work of Evan Teran.
|
||||
*
|
||||
* Copyright (c) 2008
|
||||
* Evan Teran
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted, provided
|
||||
* that the above copyright notice appears in all copies and that both the
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the same name not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. We make no representations about the
|
||||
* suitability this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*/
|
||||
|
||||
Loading…
Reference in a new issue