/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Copyright (c) 2015 Chris KAY https://github.com/cjkay-cpp-utils/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_NET_ENDIAN_HPP #define SPROUT_NET_ENDIAN_HPP #include #include #include #include namespace sprout { namespace net { namespace detail { /* * lshift_by * Left shift 'val' by 'n' bytes */ template inline SPROUT_CONSTEXPR T lshift_by(T val, std::uint_fast8_t n) { return val << (n * 8); } /* * rshift_by * Right shift 'val' by 'n' bytes */ template inline SPROUT_CONSTEXPR T rshift_by(T val, std::uint_fast8_t n) { return val >> (n * 8); } /* * mask_t * Mask 'n'th byte */ template inline SPROUT_CONSTEXPR T mask_at(std::uint_fast8_t n) { return sprout::net::detail::lshift_by(T(0xFF), n); } /* * byte_at * Get 'n'th byte from 'val' */ template inline SPROUT_CONSTEXPR std::uint_fast8_t byte_at(T val, std::uint_fast8_t n) { return static_cast( sprout::net::detail::rshift_by((val & sprout::net::detail::mask_at(n)), n) ); } /* * replace_at * Replace, in 'val', 'n'th byte with 'byte_val' */ template inline SPROUT_CONSTEXPR T replace_at(T val, std::uint8_t byte_val, std::uint_fast8_t n) { return (val & ~sprout::net::detail::mask_at(n)) | sprout::net::detail::lshift_by(T(byte_val), n); } /* * copy * Copy, in 'val', byte at index 'from' to byte at index 'to' */ template inline SPROUT_CONSTEXPR T copy(T val, std::uint_fast8_t from, std::uint_fast8_t to) { return sprout::net::detail::replace_at(val, sprout::net::detail::byte_at(val, from), to); } /* * swap * Swap, in 'val', byte at index 'n1' with byte at index 'n2' */ template inline SPROUT_CONSTEXPR T swap(T val, std::uint_fast8_t n1, std::uint_fast8_t n2) { return sprout::net::detail::replace_at(sprout::net::detail::copy(val, n1, n2), sprout::net::detail::byte_at(val, n2), n1); } /* * reverse_impl * Swap, in 'val', byte at index 'n1' with byte at index 'n2' in 'val', increment n1, decrement n2 until n1 > n2 */ template inline SPROUT_CONSTEXPR T reverse_impl(T val, std::uint_fast8_t n1, std::uint_fast8_t n2) { return n1 > n2 ? val : sprout::net::detail::reverse_impl(sprout::net::detail::swap(val, n1, n2), n1 + 1, n2 - 1); } /* * reverse * Reverse 'val' */ template inline SPROUT_CONSTEXPR T reverse(T val) { return sprout::net::detail::reverse_impl(val, 0, sizeof(T) - 1); } /* * reverse_words_impl * Swap, in 'val', byte at index 'n' - 1 with byte at index 'n' - 2, decrement n by 2 until n == 0 */ template inline SPROUT_CONSTEXPR T reverse_words_impl(T val, std::uint_fast8_t n) { return n == 0 ? val : sprout::net::detail::reverse_words_impl(swap(val, n - 1, n - 2), n - 2); } /* * reverse_words * Reverse each word in 'val' */ template inline SPROUT_CONSTEXPR T reverse_words(T val) { return sprout::net::detail::reverse_words_impl(val, sizeof(T)); } } // namespace detail // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // template<> // constexpr unsigned-integral hton(unsigned-integral host) template inline SPROUT_CONSTEXPR T hton SPROUT_PREVENT_MACRO_SUBSTITUTION (T host) { #if defined(SPROUT_BIG_ENDIAN) return host; #elif defined(SPROUT_LITTLE_ENDIAN) return sprout::net::detail::reverse(host); #elif defined(SPROUT_PDP_ENDIAN) return sprout::net::detail::reverse_words(host); #else return SPROUT_ASSERT_MSG(0, "hton: unsupported endian"), host; #endif } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // template<> // constexpr unsigned-integral ntoh(unsigned-integral net) template inline SPROUT_CONSTEXPR T ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (T net) { #if defined(SPROUT_BIG_ENDIAN) return net; #elif defined(SPROUT_LITTLE_ENDIAN) return sprout::net::detail::reverse(net); #elif defined(SPROUT_PDP_ENDIAN) return sprout::net::detail::reverse_words(host); #else return SPROUT_ASSERT_MSG(0, "ntoh: unsupported endian"), net; #endif } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint32_t htonl(uint32_t host32) inline SPROUT_CONSTEXPR std::uint32_t htonl SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint32_t host32) { return sprout::net::hton SPROUT_PREVENT_MACRO_SUBSTITUTION (host32); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint16_t htons(uint16_t host16) inline SPROUT_CONSTEXPR std::uint16_t htons SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint16_t host16) { return sprout::net::hton SPROUT_PREVENT_MACRO_SUBSTITUTION (host16); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint32_t ntohl(uint32_t net32) inline SPROUT_CONSTEXPR std::uint32_t ntohl SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint32_t net32) { return sprout::net::ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (net32); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint16_t ntohs(uint32_t net16) inline SPROUT_CONSTEXPR std::uint16_t ntohs SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint16_t net16) { return sprout::net::ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (net16); } } //namespace net } // namespace sprout #endif // #ifndef SPROUT_NET_ENDIAN_HPP