This class is meant to work exactly as an unsigned integer should work, but it limits the value based on a set amount of bits.
/**
* @brief Any amount of bits integer.
* @tparam bits amount of bits
*
* @note stores with size of uint64_t
*/
template <uint8_t bits>
requires((bits >= 1) && (bits <= 64))
class uintx_t {
protected:
uint64_t Val;
constexpr static inline uint64_t formatBits(
uint64_t val,
uint16_t bits2
) {return val & (UINT64_MAX >> (64-bits2));}
public:
uintx_t(int64_t val) {
Val = formatBits(val, bits);
}
template <uint8_t otherBits>
uintx_t(const uintx_t<otherBits>& val) {
Val = formatBits(val.getVal(), bits);
}
constexpr inline uint64_t getVal() const {return Val;}
std::string toBin() const {
std::string bin = std::bitset<bits>(Val).to_string();
return bin;
}
inline void operator= (int64_t val) {
Val = formatBits(val, bits);
}
template <uint8_t otherBits>
inline void operator= (uintx_t<otherBits> val) {
Val = formatBits(val.getVal(), bits);
}
inline bool operator== (int64_t val) {
return (Val == val);
}
template <uint8_t otherBits>
inline bool operator==(const uintx_t<otherBits>& val) {
return (Val == val.getVal());
}
inline bool operator!= (int64_t val) {
return (Val != val);
}
template <uint8_t otherBits>
inline bool operator!=(const uintx_t<otherBits>& val) {
return (Val != val.getVal());
}
inline bool operator> (int64_t val) {
return (Val > val);
}
template <uint8_t otherBits>
inline bool operator> (const uintx_t<otherBits>& val) {
return (Val > val.getVal());
}
inline bool operator< (int64_t val) {
return (Val < val);
}
template <uint8_t otherBits>
inline bool operator< (const uintx_t<otherBits>& val) {
return (Val < val.getVal());
}
inline bool operator>= (int64_t val) {
return (Val >= val);
}
template <uint8_t otherBits>
inline bool operator>= (const uintx_t<otherBits>& val) {
return (Val >= val.getVal());
}
inline bool operator<= (int64_t val) {
return (Val <= val);
}
template <uint8_t otherBits>
inline bool operator<= (const uintx_t<otherBits>& val) {
return (Val <= val.getVal());
}
inline uintx_t operator+ (int64_t val) {
return uintx_t(formatBits(Val + val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator+ (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val + val.getVal(), bits));
}
inline uintx_t operator- (int64_t val) {
return uintx_t(formatBits(Val - val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator- (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val - val.getVal(), bits));
}
inline uintx_t operator* (int64_t val) {
return uintx_t(formatBits(Val * val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator* (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val * val.getVal(), bits));
}
inline uintx_t operator/ (int64_t val) {
return uintx_t(formatBits(Val / val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator/ (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val / val.getVal(), bits));
}
inline uintx_t operator% (int64_t val) {
return uintx_t(formatBits(Val % val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator% (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val % val.getVal(), bits));
}
inline uintx_t operator| (int64_t val) {
return uintx_t(formatBits(Val | val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator| (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val | val.getVal(), bits));
}
inline uintx_t operator& (int64_t val) {
return uintx_t(formatBits(Val & val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator& (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val & val.getVal(), bits));
}
inline uintx_t operator^ (int64_t val) {
return uintx_t(formatBits(Val ^ val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator^ (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val ^ val.getVal(), bits));
}
inline uintx_t operator<< (int64_t val) {
return uintx_t(formatBits(Val << val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator<< (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val << val.getVal(), bits));
}
inline uintx_t operator>> (int64_t val) {
return uintx_t(formatBits(Val >> val, bits));
}
template <uint8_t otherBits>
inline uintx_t operator>> (const uintx_t<otherBits>& val) {
return uintx_t(formatBits(Val >> val.getVal(), bits));
}
inline uintx_t& operator++ () {
Val = formatBits(++Val, bits);
return *this;
}
inline uintx_t& operator-- () {
Val = formatBits(--Val, bits);
return *this;
}
inline uintx_t operator++ (int) {
Val = formatBits(++Val, bits);
return *this;
}
inline uintx_t operator-- (int) {
Val = formatBits(--Val, bits);
return *this;
}
inline uintx_t operator+= (int64_t val) {
Val = formatBits(Val+val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator+= (const uintx_t<otherBits>& val) {
Val = formatBits(Val+val.getVal(), bits);
return *this;
}
inline uintx_t operator-= (int64_t val) {
Val = formatBits(Val-val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator-= (const uintx_t<otherBits>& val) {
Val = formatBits(Val-val.getVal(), bits);
return *this;
}
inline uintx_t operator*= (int64_t val) {
Val = formatBits(Val*val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator*= (const uintx_t<otherBits>& val) {
Val = formatBits(Val*val.getVal(), bits);
return *this;
}
inline uintx_t operator/= (int64_t val) {
Val = formatBits(Val/val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator/= (const uintx_t<otherBits>& val) {
Val = formatBits(Val/val.getVal(), bits);
return *this;
}
inline uintx_t operator%= (int64_t val) {
Val = formatBits(Val%val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator%= (const uintx_t<otherBits>& val) {
Val = formatBits(Val%val.getVal(), bits);
return *this;
}
inline uintx_t operator|= (int64_t val) {
Val = formatBits(Val|val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator|= (const uintx_t<otherBits>& val) {
Val = formatBits(Val|val.getVal(), bits);
return *this;
}
inline uintx_t operator&= (int64_t val) {
Val = formatBits(Val&val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator&= (const uintx_t<otherBits>& val) {
Val = formatBits(Val&val.getVal(), bits);
return *this;
}
inline uintx_t operator^= (int64_t val) {
Val = formatBits(Val^val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator^= (const uintx_t<otherBits>& val) {
Val = formatBits(Val^val.getVal(), bits);
return *this;
}
inline uintx_t operator<<= (int64_t val) {
Val = formatBits(Val<<val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator<<= (const uintx_t<otherBits>& val) {
Val = formatBits(Val<<val.getVal(), bits);
return *this;
}
inline uintx_t operator>>= (int64_t val) {
Val = formatBits(Val>>val, bits);
return *this;
}
template <uint8_t otherBits>
inline uintx_t operator>>= (const uintx_t<otherBits>& val) {
Val = formatBits(Val>>val.getVal(), bits);
return *this;
}
friend std::ostream& operator<< (
std::ostream& os,
uintx_t& UX
) {
os << std::to_string(UX.Val);
return os;
}
template <typename T>
explicit operator T() const {
return (T)Val;
}
};
Example:
uintx_t<4> nibble = 3;
uintx_t<8> other = 20;
std::cout << nibble << '\n';
std::cout << nibble.toBin() << '\n';
std::cout << nibble + 4 << '\n';
std::cout << nibble + other << '\n';
Output:
3
0011
7
7