ostinato/common/uint128.h
2021-12-08 21:36:39 +05:30

233 lines
5.1 KiB
C++

/*
Copyright (C) 2015 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef _UINT128_H
#define _UINT128_H
#include <QHash>
#include <QDebug>
#include <QtGlobal>
#include <qendian.h>
class UInt128
{
public:
UInt128();
UInt128(int lo);
UInt128(quint64 hi, quint64 lo);
UInt128(quint8 *value);
quint64 hi64() const;
quint64 lo64() const;
quint8* toArray() const;
bool operator!() const;
bool operator==(const UInt128 &other) const;
bool operator!=(const UInt128 &other) const;
UInt128 operator+(const UInt128 &other) const;
UInt128 operator-(const UInt128 &other) const;
UInt128 operator*(const uint &other) const;
UInt128 operator<<(const int &shift) const;
UInt128 operator~() const;
UInt128 operator&(const UInt128 &other) const;
UInt128 operator|(const UInt128 &other) const;
private:
quint64 hi_;
quint64 lo_;
quint8 array_[16];
};
Q_DECLARE_METATYPE(UInt128);
inline UInt128::UInt128()
{
// Do nothing - value will be garbage like any other uint
}
inline UInt128::UInt128(int lo)
{
hi_ = 0;
lo_ = lo;
}
inline UInt128::UInt128(quint64 hi, quint64 lo)
{
hi_ = hi;
lo_ = lo;
}
inline UInt128::UInt128(quint8 *value)
{
hi_ = (quint64(value[0]) << 56)
| (quint64(value[1]) << 48)
| (quint64(value[2]) << 40)
| (quint64(value[3]) << 32)
| (quint64(value[4]) << 24)
| (quint64(value[5]) << 16)
| (quint64(value[6]) << 8)
| (quint64(value[7]) << 0);
lo_ = (quint64(value[ 8]) << 56)
| (quint64(value[ 9]) << 48)
| (quint64(value[10]) << 40)
| (quint64(value[11]) << 32)
| (quint64(value[12]) << 24)
| (quint64(value[13]) << 16)
| (quint64(value[14]) << 8)
| (quint64(value[15]) << 0);
}
inline quint64 UInt128::hi64() const
{
return hi_;
}
inline quint64 UInt128::lo64() const
{
return lo_;
}
inline quint8* UInt128::toArray() const
{
qToBigEndian(hi_, const_cast<uchar*>(array_ + 0));
qToBigEndian(lo_, const_cast<uchar*>(array_ + 8));
return (quint8*)array_;
}
inline bool UInt128::operator!() const
{
return (hi_ == 0) && (lo_ == 0);
}
inline bool UInt128::operator==(const UInt128 &other) const
{
return ((hi_ == other.hi_) && (lo_ == other.lo_));
}
inline bool UInt128::operator!=(const UInt128 &other) const
{
return ((hi_ != other.hi_) || (lo_ != other.lo_));
}
inline UInt128 UInt128::operator+(const UInt128 &other) const
{
UInt128 sum;
sum.lo_ = lo_ + other.lo_;
sum.hi_ = hi_ + other.hi_ + (sum.lo_ < lo_);
return sum;
}
inline UInt128 UInt128::operator-(const UInt128 &other) const
{
UInt128 diff;
diff.lo_ = lo_ - other.lo_;
diff.hi_ = hi_ - other.hi_ - (diff.lo_ > lo_);
return diff;
}
inline UInt128 UInt128::operator*(const uint &other) const
{
UInt128 product;
// FIXME
product.hi_ = 0;
product.lo_ = lo_ * other;
return product;
}
inline UInt128 UInt128::operator<<(const int &shift) const
{
UInt128 shifted;
if (shift < 64)
return UInt128((hi_<<shift) | (lo_>>(64-shift)), lo_ << shift);
return UInt128(hi_<<(shift-64), 0);
}
inline UInt128 UInt128::operator~() const
{
return UInt128(~hi_, ~lo_);
}
inline UInt128 UInt128::operator&(const UInt128 &other) const
{
return UInt128(hi_ & other.hi_, lo_ & other.lo_);
}
inline UInt128 UInt128::operator|(const UInt128 &other) const
{
return UInt128(hi_ | other.hi_, lo_ | other.lo_);
}
#if QT_VERSION >= 0x050700
template <> inline UInt128 qFromBigEndian<UInt128>(const void *src)
#else
template <> inline UInt128 qFromBigEndian<UInt128>(const uchar *src)
#endif
{
quint64 hi, lo;
hi = qFromBigEndian<quint64>(src);
lo = qFromBigEndian<quint64>((uchar*)src+8);
return UInt128(hi, lo);
}
#if QT_VERSION >= 0x050700
template <> inline void qToBigEndian<UInt128>(UInt128 src, void *dest)
#else
template <> inline void qToBigEndian<UInt128>(UInt128 src, uchar *dest)
#endif
{
memcpy(dest, src.toArray(), 16);
}
template <> inline UInt128 qToBigEndian<UInt128>(const UInt128 src)
{
quint64 hi, lo;
hi = qToBigEndian<quint64>(src.hi64());
lo = qToBigEndian<quint64>(src.lo64());
return UInt128(hi, lo);
}
inline QDebug operator<<(QDebug debug, const UInt128 &value)
{
QDebugStateSaver saver(debug);
debug.maybeSpace() << hex << value.hi64() << " " << value.lo64();
return debug;
}
inline uint qHash(const UInt128 &key)
{
return qHash(key.hi64()) ^ qHash(key.lo64());
}
#endif