125 lines
2.8 KiB
C++
125 lines
2.8 KiB
C++
|
#pragma once
|
||
|
|
||
|
#include <pd/core/common.hpp>
|
||
|
|
||
|
namespace PD {
|
||
|
/**
|
||
|
* 128 Bit support for all platforms probably
|
||
|
* only used for flag checks in Keyboard/Mouse Input driver
|
||
|
*/
|
||
|
class u128 {
|
||
|
public:
|
||
|
u64 pLow = 0;
|
||
|
u64 pHigh = 0;
|
||
|
|
||
|
constexpr u128() : pLow(0), pHigh(0) {}
|
||
|
constexpr u128(u64 l, u64 h = 0) : pLow(l), pHigh(h) {}
|
||
|
|
||
|
/**
|
||
|
* Best way so far to create flags that go over 63
|
||
|
* like `1 << 65` is just `u128::Flag(65)`
|
||
|
*/
|
||
|
constexpr static u128 Flag(u32 i) {
|
||
|
if (i < 64) {
|
||
|
return u128(1ULL << i, 0);
|
||
|
} else if (i < 128) {
|
||
|
return u128(0, 1ULL << (i - 64));
|
||
|
}
|
||
|
return u128();
|
||
|
}
|
||
|
|
||
|
u128 operator+(const u128& v) const {
|
||
|
u128 ret;
|
||
|
ret.pLow = pLow + v.pLow;
|
||
|
ret.pHigh = pHigh + v.pHigh + (ret.pLow < pLow);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
u128 operator&(const u128& v) const {
|
||
|
return u128(pLow & v.pLow, pHigh & v.pHigh);
|
||
|
}
|
||
|
|
||
|
u128 operator<<(u32 s) const {
|
||
|
if (s == 0) {
|
||
|
return *this;
|
||
|
}
|
||
|
if (s >= 128) {
|
||
|
return u128();
|
||
|
}
|
||
|
if (s >= 64) {
|
||
|
return u128(0, pLow << (s - 64));
|
||
|
}
|
||
|
return u128(pLow << s, (pHigh << s) | (pLow >> (64 - s)));
|
||
|
}
|
||
|
|
||
|
u128 operator>>(u32 s) const {
|
||
|
if (s == 0) {
|
||
|
return *this;
|
||
|
}
|
||
|
if (s >= 128) {
|
||
|
return u128();
|
||
|
}
|
||
|
if (s >= 64) {
|
||
|
return u128(pHigh >> (s - 64), 0);
|
||
|
}
|
||
|
return u128((pLow >> s) | (pHigh << (64 - s)), pHigh >> s);
|
||
|
}
|
||
|
|
||
|
u128& operator|=(const u128& v) {
|
||
|
pLow |= v.pLow;
|
||
|
pHigh |= v.pHigh;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
u128 operator|(const u128& v) const {
|
||
|
return u128(pLow | v.pLow, pHigh | v.pHigh);
|
||
|
}
|
||
|
|
||
|
u128& operator&=(const u128& v) {
|
||
|
pLow &= v.pLow;
|
||
|
pHigh &= v.pHigh;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
u128 operator~() const { return u128(~pLow, ~pHigh); }
|
||
|
|
||
|
/**
|
||
|
* Old why to make if checks possible
|
||
|
* Problem was that a operator& is required
|
||
|
* with u128 as result
|
||
|
*/
|
||
|
// bool operator&(const u128& v) const {
|
||
|
// return pLow & v.pLow || pHigh & v.pHigh;
|
||
|
// }
|
||
|
|
||
|
bool operator==(const u128& v) const {
|
||
|
return pLow == v.pLow && pHigh == v.pHigh;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Use explicit here to make sure it is only for checking and not for
|
||
|
* some error leading implicit bool assignments...
|
||
|
*/
|
||
|
explicit operator bool() const { return pLow != 0 || pHigh != 0; }
|
||
|
|
||
|
/** Deprecated way to handle `flag & SomeFlag` */
|
||
|
bool Has(const u128& v) const { return pLow & v.pLow || pHigh & v.pHigh; }
|
||
|
|
||
|
bool operator!=(const u128& v) const { return !(*this == v); }
|
||
|
};
|
||
|
} // namespace PD
|
||
|
|
||
|
namespace std {
|
||
|
/**
|
||
|
* Provide c++ STL support for unordered map to u128
|
||
|
*/
|
||
|
template <>
|
||
|
struct hash<PD::u128> {
|
||
|
size_t operator()(const PD::u128& k) const {
|
||
|
// just combine hashes of the parts usign simple xor op
|
||
|
size_t h0 = std::hash<PD::u64>{}(k.pLow);
|
||
|
size_t h1 = std::hash<PD::u64>{}(k.pHigh);
|
||
|
return h0 ^ (h1 << 1);
|
||
|
}
|
||
|
};
|
||
|
} // namespace std
|