albyte.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #ifndef AL_BYTE_H
  2. #define AL_BYTE_H
  3. #include <cstddef>
  4. #include <limits>
  5. #include <type_traits>
  6. namespace al {
  7. /* The "canonical" way to store raw byte data. Like C++17's std::byte, it's not
  8. * treated as a character type and does not work with arithmatic ops. Only
  9. * bitwise ops are allowed.
  10. */
  11. enum class byte : unsigned char { };
  12. #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),bool>::type = true
  13. template<typename T, REQUIRES(std::is_integral<T>::value)>
  14. inline constexpr T to_integer(al::byte b) noexcept { return T(b); }
  15. template<typename T, REQUIRES(std::is_integral<T>::value)>
  16. inline constexpr al::byte operator<<(al::byte lhs, T rhs) noexcept
  17. { return al::byte(to_integer<unsigned int>(lhs) << rhs); }
  18. template<typename T, REQUIRES(std::is_integral<T>::value)>
  19. inline constexpr al::byte operator>>(al::byte lhs, T rhs) noexcept
  20. { return al::byte(to_integer<unsigned int>(lhs) >> rhs); }
  21. template<typename T, REQUIRES(std::is_integral<T>::value)>
  22. inline al::byte& operator<<=(al::byte &lhs, T rhs) noexcept
  23. { lhs = lhs << rhs; return lhs; }
  24. template<typename T, REQUIRES(std::is_integral<T>::value)>
  25. inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept
  26. { lhs = lhs >> rhs; return lhs; }
  27. #define AL_DECL_OP(op) \
  28. template<typename T, REQUIRES(std::is_integral<T>::value)> \
  29. inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \
  30. { return al::byte(to_integer<unsigned int>(lhs) op static_cast<unsigned int>(rhs)); } \
  31. template<typename T, REQUIRES(std::is_integral<T>::value)> \
  32. inline al::byte& operator op##= (al::byte &lhs, T rhs) noexcept \
  33. { lhs = lhs op rhs; return lhs; } \
  34. inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \
  35. { return al::byte(lhs op to_integer<unsigned int>(rhs)); } \
  36. inline al::byte& operator op##= (al::byte &lhs, al::byte rhs) noexcept \
  37. { lhs = lhs op rhs; return lhs; }
  38. AL_DECL_OP(|)
  39. AL_DECL_OP(&)
  40. AL_DECL_OP(^)
  41. #undef AL_DECL_OP
  42. inline constexpr al::byte operator~(al::byte b) noexcept
  43. { return al::byte(~to_integer<unsigned int>(b)); }
  44. template<size_t N>
  45. class bitfield {
  46. static constexpr size_t bits_per_byte{std::numeric_limits<unsigned char>::digits};
  47. static constexpr size_t NumElems{(N+bits_per_byte-1) / bits_per_byte};
  48. byte vals[NumElems]{};
  49. public:
  50. template<size_t b>
  51. inline void set() noexcept
  52. {
  53. static_assert(b < N, "Bit index out of range");
  54. vals[b/bits_per_byte] |= 1 << (b%bits_per_byte);
  55. }
  56. template<size_t b>
  57. inline void unset() noexcept
  58. {
  59. static_assert(b < N, "Bit index out of range");
  60. vals[b/bits_per_byte] &= ~(1 << (b%bits_per_byte));
  61. }
  62. template<size_t b>
  63. inline bool get() const noexcept
  64. {
  65. static_assert(b < N, "Bit index out of range");
  66. return (vals[b/bits_per_byte] & (1 << (b%bits_per_byte))) != byte{};
  67. }
  68. template<size_t b, size_t ...args, REQUIRES(sizeof...(args) > 0)>
  69. void set() noexcept
  70. {
  71. set<b>();
  72. set<args...>();
  73. }
  74. };
  75. #undef REQUIRES
  76. } // namespace al
  77. #endif /* AL_BYTE_H */