/** * @file libimp/byte.h * @author mutouyun (orz@orzz.org) * @brief Define the byte type. * @date 2022-11-12 */ #pragma once #include #include #include // std::byte (since C++17) #include "libimp/def.h" #include "libimp/detect_plat.h" #include "libimp/span.h" #include "libimp/fmt.h" #if defined(LIBIMP_CPP_17) && defined(__cpp_lib_byte) #define LIBIMP_CPP_LIB_BYTE_ #endif // __cpp_lib_byte LIBIMP_NAMESPACE_BEG_ class byte; namespace detail { template using is_integral = typename std::enable_if::value>::type; template using is_not_byte = typename std::enable_if::type, byte>::value>::type; } // namespace detail /** * @brief A distinct type that implements the concept of byte as specified in the C++ language definition. * @see https://en.cppreference.com/w/cpp/types/byte */ class byte { std::uint8_t bits_; public: constexpr byte() noexcept : byte(0) {} template > constexpr byte(T v) noexcept : bits_(static_cast(v)) {} #ifdef LIBIMP_CPP_LIB_BYTE_ constexpr byte(std::byte b) noexcept : byte(std::to_integer(b)) {} #endif // LIBIMP_CPP_LIB_BYTE_ template > explicit constexpr operator T() const noexcept { return static_cast(bits_); } #ifdef LIBIMP_CPP_LIB_BYTE_ explicit constexpr operator std::byte() const noexcept { /// @brief C++17 relaxed enum class initialization rules. /// @see https://en.cppreference.com/w/cpp/language/enum#enum_relaxed_init_cpp17 return std::byte{bits_}; } #endif // LIBIMP_CPP_LIB_BYTE_ friend bool operator==(byte const &lhs, byte const &rhs) noexcept { return lhs.bits_ == rhs.bits_; } friend bool operator!=(byte const &lhs, byte const &rhs) noexcept { return !(lhs == rhs); } }; /** * @brief Non-member functions. */ template > constexpr T to_integer(byte b) noexcept { return T(b); } /// @brief std::operator<<, operator>> template > constexpr byte operator<<(byte b, T shift) noexcept { return byte(to_integer(b) << shift); } template > constexpr byte operator>>(byte b, T shift) noexcept { return byte(to_integer(b) >> shift); } /// @brief std::operator<<=, operator>>= template > constexpr byte &operator<<=(byte &b, T shift) noexcept { return b = b << shift; } template > constexpr byte &operator>>=(byte &b, T shift) noexcept { return b = b >> shift; } /// @brief std::operator|, operator&, operator^, operator~ constexpr byte operator|(byte l, byte r) noexcept { return byte(to_integer(l) | to_integer(r)); } constexpr byte operator&(byte l, byte r) noexcept { return byte(to_integer(l) & to_integer(r)); } constexpr byte operator^(byte l, byte r) noexcept { return byte(to_integer(l) ^ to_integer(r)); } constexpr byte operator~(byte b) noexcept { return byte(~to_integer(b)); } /// @brief std::operator|=, operator&=, operator^= constexpr byte &operator|=(byte &l, byte r) noexcept { return l = l | r; } constexpr byte &operator&=(byte &l, byte r) noexcept { return l = l & r; } constexpr byte &operator^=(byte &l, byte r) noexcept { return l = l ^ r; } /// @brief Cast pointer to byte*. template > byte *byte_cast(T *p) noexcept { return reinterpret_cast(p); } template > byte const *byte_cast(T const *p) noexcept { return reinterpret_cast(p); } /// @brief Cast byte* to a pointer of another type. template > T *byte_cast(byte *p) noexcept { if (reinterpret_cast(p) % alignof(T) != 0) { return nullptr; } return reinterpret_cast(p); } template ::type, typename = detail::is_not_byte> U *byte_cast(byte const *p) noexcept { if (reinterpret_cast(p) % alignof(T) != 0) { return nullptr; } return reinterpret_cast(p); } /// @brief Converts a span into a view of its underlying bytes. /// @see https://en.cppreference.com/w/cpp/container/span/as_bytes template ::value, byte const, byte>::type> auto as_bytes(span s) noexcept -> span { return {byte_cast(s.data()), s.size_bytes()}; } /// @brief Custom defined fmt_to method for imp::fmt namespace detail { inline bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, ::LIBIMP::byte b) { return ::LIBIMP::to_string(ctx, static_cast(b), "02x"); } template , ::LIBIMP::byte>::value>> bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, fmt_ref arg) noexcept { return ::LIBIMP::to_string(ctx, static_cast(arg.param), arg.fstr); } } // namespace detail LIBIMP_NAMESPACE_END_