#ifndef BYTE_ORDER_HPP_LPUJ094I #define BYTE_ORDER_HPP_LPUJ094I #include #include #include #include #include namespace vanetza { template T hton(T host_value) { return boost::endian::native_to_big(host_value); } template T ntoh(T network_value) { return boost::endian::big_to_native(network_value); } enum class ByteOrder { BigEndian, LittleEndian }; namespace detail { #if BYTE_ORDER == LITTLE_ENDIAN static constexpr ByteOrder host_byte_order = ByteOrder::LittleEndian; #elif BYTE_ORDER == BIG_ENDIAN static constexpr ByteOrder host_byte_order = ByteOrder::BigEndian; #else # error "Unknown byte order" #endif } // namespace detail constexpr ByteOrder getHostByteOrder() { return detail::host_byte_order; } template class EndianType; /** * Explicitly forge a plain type to an EndianType. * It is assumed the passed value is already in the stated byte order, * i.e. endian_cast does _not_ trigger any automatic conversions. * \param value A plain value in byte order ORDER * \return EndianType capable to carry value type */ template EndianType endian_cast(T value) { return static_cast< EndianType >(value); } /** * Cast POD type to EndianType in host byte order * \param value POD in host byte order * \return EndianType carrying value */ template EndianType host_cast(T value) { return endian_cast(value); } /** * Cast POD type to EndianType in network byte order * \param value POD in network byte order * \return EndianType carrying value */ template EndianType network_cast(T value) { return endian_cast(value); } namespace detail { template struct EndianConverter { T operator()(const T&) const; }; template struct EndianConverter { T operator()(const T& t) const { return t; } }; template struct EndianConverter { T operator()(const T& t) const { return boost::endian::endian_reverse(t); } }; template struct EndianConverter { T operator()(const T& t) const { return boost::endian::endian_reverse(t); } }; template T convert_endian(const T& t) { EndianConverter converter; return converter(t); } } // namespace detail template class EndianType { public: static_assert(std::is_arithmetic::value == true, "EndianType is only availabe for arithmetic types"); typedef T value_type; typedef EndianType host_type; typedef EndianType network_type; EndianType() = default; explicit EndianType(T value) { m_value = value; } EndianType(const EndianType&) = default; EndianType& operator=(const EndianType&) = default; template EndianType(const EndianType& other) : m_value(detail::convert_endian(other.m_value)) { } template EndianType& operator=(const EndianType& other) { m_value = detail::convert_endian(other.m_value); return *this; } bool operator==(const EndianType& other) const { return m_value == other.m_value; } bool operator!=(const EndianType& other) const { return !(*this == other); } bool operator<(const EndianType& other) const { return m_value < other.m_value; } value_type net() const { return detail::convert_endian(m_value); } value_type host() const { return detail::convert_endian(m_value); } value_type get() const { return m_value; } private: friend class EndianType; friend class EndianType; T m_value; }; /** * Print to ostream in network byte order * \param os output stream * \param t endian type object * \return os */ template std::ostream& operator<<(std::ostream& os, const EndianType& t) { os << t.net(); return os; } typedef EndianType uint8be_t; typedef EndianType uint16be_t; typedef EndianType uint32be_t; typedef EndianType uint64be_t; typedef EndianType int8be_t; typedef EndianType int16be_t; typedef EndianType int32be_t; typedef EndianType int64be_t; } // namespace vanetza namespace std { template struct hash> { size_t operator()(const vanetza::EndianType& t) const { return hash()(t.get()); } }; } // namespace std #endif /* BYTE_ORDER_HPP_LPUJ094I */