11 /* The "canonical" way to store raw byte data. Like C++17's std::byte, it's not
12 * treated as a character type and does not work with arithmatic ops. Only
13 * bitwise ops are allowed.
15 enum class byte
: unsigned char { };
17 #define REQUIRES(...) std::enable_if_t<(__VA_ARGS__),bool> = true
19 template<typename T
, REQUIRES(std::is_integral
<T
>::value
)>
20 inline constexpr T
to_integer(al::byte b
) noexcept
{ return T(b
); }
23 template<typename T
, REQUIRES(std::is_integral
<T
>::value
)>
24 inline constexpr al::byte
operator<<(al::byte lhs
, T rhs
) noexcept
25 { return al::byte(to_integer
<unsigned int>(lhs
) << rhs
); }
27 template<typename T
, REQUIRES(std::is_integral
<T
>::value
)>
28 inline constexpr al::byte
operator>>(al::byte lhs
, T rhs
) noexcept
29 { return al::byte(to_integer
<unsigned int>(lhs
) >> rhs
); }
31 template<typename T
, REQUIRES(std::is_integral
<T
>::value
)>
32 inline al::byte
& operator<<=(al::byte
&lhs
, T rhs
) noexcept
33 { lhs
= lhs
<< rhs
; return lhs
; }
35 template<typename T
, REQUIRES(std::is_integral
<T
>::value
)>
36 inline al::byte
& operator>>=(al::byte
&lhs
, T rhs
) noexcept
37 { lhs
= lhs
>> rhs
; return lhs
; }
39 #define AL_DECL_OP(op, opeq) \
40 template<typename T, REQUIRES(std::is_integral<T>::value)> \
41 inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \
42 { return al::byte(to_integer<unsigned int>(lhs) op static_cast<unsigned int>(rhs)); } \
43 template<typename T, REQUIRES(std::is_integral<T>::value)> \
44 inline al::byte& operator opeq (al::byte &lhs, T rhs) noexcept \
45 { lhs = lhs op rhs; return lhs; } \
46 inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \
47 { return al::byte(lhs op to_integer<unsigned int>(rhs)); } \
48 inline al::byte& operator opeq (al::byte &lhs, al::byte rhs) noexcept \
49 { lhs = lhs op rhs; return lhs; }
57 inline constexpr al::byte
operator~(al::byte b
) noexcept
58 { return al::byte(~to_integer
<unsigned int>(b
)); }
62 template<size_t> struct Elem
{ };
63 template<> struct Elem
<1> { using type
= uint8_t; };
64 template<> struct Elem
<2> { using type
= uint16_t; };
65 template<> struct Elem
<3> { using type
= uint32_t; };
66 template<> struct Elem
<4> { using type
= uint32_t; };
68 template<size_t N
> using ElemT
= typename Elem
<N
>::type
;
69 } // namespace detail_
73 static constexpr size_t bits_per_byte
{std::numeric_limits
<unsigned char>::digits
};
74 static constexpr size_t NumElems
{(N
+bits_per_byte
-1) / bits_per_byte
};
76 using storage_type
= detail_::ElemT
<NumElems
>;
81 inline void set() noexcept
83 static_assert(b
< N
, "Bit index out of range");
87 inline void unset() noexcept
89 static_assert(b
< N
, "Bit index out of range");
90 vals
&= static_cast<storage_type
>(~(1 << b
));
93 inline bool get() const noexcept
95 static_assert(b
< N
, "Bit index out of range");
96 return (vals
& (1 << b
)) != 0;
99 template<size_t b
, size_t ...args
, REQUIRES(sizeof...(args
) > 0)>
111 #endif /* AL_BYTE_H */