1 #ifndef AL_BYTE_H
2 #define AL_BYTE_H
3 
4 #include <cstddef>
5 #include <cstdint>
6 #include <limits>
7 #include <type_traits>
8 
9 using uint = unsigned int;
10 
11 namespace al {
12 
13 /* The "canonical" way to store raw byte data. Like C++17's std::byte, it's not
14  * treated as a character type and does not work with arithmatic ops. Only
15  * bitwise ops are allowed.
16  */
17 enum class byte : unsigned char { };
18 
19 template<typename T>
20 constexpr std::enable_if_t<std::is_integral<T>::value,T>
to_integer(al::byte b)21 to_integer(al::byte b) noexcept { return T(b); }
22 
23 
24 template<typename T>
25 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte>
26 operator<<(al::byte lhs, T rhs) noexcept { return al::byte(to_integer<uint>(lhs) << rhs); }
27 
28 template<typename T>
29 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte>
30 operator>>(al::byte lhs, T rhs) noexcept { return al::byte(to_integer<uint>(lhs) >> rhs); }
31 
32 template<typename T>
33 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&>
34 operator<<=(al::byte &lhs, T rhs) noexcept { lhs = lhs << rhs; return lhs; }
35 
36 template<typename T>
37 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&>
38 operator>>=(al::byte &lhs, T rhs) noexcept { lhs = lhs >> rhs; return lhs; }
39 
40 #define AL_DECL_OP(op, opeq)                                                  \
41 template<typename T>                                                          \
42 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte>               \
43 operator op (al::byte lhs, T rhs) noexcept                                    \
44 { return al::byte(to_integer<uint>(lhs) op static_cast<uint>(rhs)); }         \
45                                                                               \
46 template<typename T>                                                          \
47 constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&>              \
48 operator opeq (al::byte &lhs, T rhs) noexcept { lhs = lhs op rhs; return lhs; } \
49                                                                               \
50 constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept          \
51 { return al::byte(lhs op to_integer<uint>(rhs)); }                            \
52                                                                               \
53 constexpr al::byte& operator opeq (al::byte &lhs, al::byte rhs) noexcept      \
54 { lhs = lhs op rhs; return lhs; }
55 
56 AL_DECL_OP(|, |=)
57 AL_DECL_OP(&, &=)
58 AL_DECL_OP(^, ^=)
59 
60 #undef AL_DECL_OP
61 
62 constexpr al::byte operator~(al::byte b) noexcept
63 { return al::byte(~to_integer<uint>(b)); }
64 
65 } // namespace al
66 
67 #endif /* AL_BYTE_H */
68