/** * \file libipc/byte.h * \author mutouyun (orz@orzz.org) * \brief Define the byte type. */ #pragma once #include #include #include // std::byte (since C++17) #include "libipc/imp/detect_plat.h" #include "libipc/imp/span.h" #if defined(LIBIPC_CPP_17) && defined(__cpp_lib_byte) #define LIBIPC_CPP_LIB_BYTE_ #endif // __cpp_lib_byte namespace ipc { class byte; namespace detail_byte { 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_byte /** * \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: byte() noexcept = default; template > constexpr byte(T v) noexcept : bits_(static_cast(v)) {} #ifdef LIBIPC_CPP_LIB_BYTE_ constexpr byte(std::byte b) noexcept : byte(std::to_integer(b)) {} #endif // LIBIPC_CPP_LIB_BYTE_ template > constexpr operator T() const noexcept { return static_cast(bits_); } #ifdef LIBIPC_CPP_LIB_BYTE_ 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 // LIBIPC_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_byte::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()}; } } // namespace ipc