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
 |