types: Add constexpr endianness functions

Change-Id: I3ceff6cbd6d1991dc6131d266fa61dbf76595fdb
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/types.cpp b/src/types.cpp
index 12a4363..55c6d10 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -1,8 +1,5 @@
 #include "types.hpp"
 
-#include <arpa/inet.h>
-#include <byteswap.h>
-
 #include <charconv>
 
 namespace phosphor::network::detail
@@ -29,7 +26,7 @@
 
 std::string_view AddrBufMaker<in_addr>::operator()(in_addr val) noexcept
 {
-    auto v = bswap_32(ntohl(val.s_addr));
+    auto v = bswap(ntoh(val.s_addr));
     char* ptr = buf.begin();
     for (size_t i = 0; i < 3; ++i)
     {
@@ -84,7 +81,7 @@
             continue;
         }
         const auto res =
-            std::to_chars(ptr, buf.end(), ntohs(val.s6_addr16[i]), 16);
+            std::to_chars(ptr, buf.end(), ntoh(val.s6_addr16[i]), 16);
         ptr = res.ptr;
         if (i < 7)
         {
diff --git a/src/types.hpp b/src/types.hpp
index 79f1be4..75db6a4 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -6,6 +6,7 @@
 #include <algorithm>
 #include <array>
 #include <chrono>
+#include <numeric>
 #include <sdeventplus/clock.hpp>
 #include <sdeventplus/utility/timer.hpp>
 #include <string>
@@ -59,6 +60,91 @@
 namespace detail
 {
 
+template <typename T, uint8_t size = sizeof(T)>
+struct BswapAlign
+{
+    using type = T;
+};
+
+template <typename T>
+struct BswapAlign<T, 2>
+{
+    using type alignas(uint16_t) = T;
+};
+
+template <typename T>
+struct BswapAlign<T, 4>
+{
+    using type alignas(uint32_t) = T;
+};
+
+template <typename T>
+struct BswapAlign<T, 8>
+{
+    using type alignas(uint64_t) = T;
+};
+
+template <typename T>
+constexpr T bswapInt(typename BswapAlign<T>::type n) noexcept
+{
+    static_assert(std::is_trivially_copyable_v<T>);
+    if constexpr (sizeof(T) == 2)
+    {
+        reinterpret_cast<uint16_t&>(n) =
+            __builtin_bswap16(reinterpret_cast<uint16_t&>(n));
+    }
+    else if constexpr (sizeof(T) == 4)
+    {
+        reinterpret_cast<uint32_t&>(n) =
+            __builtin_bswap32(reinterpret_cast<uint32_t&>(n));
+    }
+    else if constexpr (sizeof(T) == 8)
+    {
+        reinterpret_cast<uint64_t&>(n) =
+            __builtin_bswap64(reinterpret_cast<uint64_t&>(n));
+    }
+    else
+    {
+        auto b = reinterpret_cast<std::byte*>(&n);
+        std::reverse(b, b + sizeof(n));
+    }
+    return n;
+}
+
+} // namespace detail
+
+template <typename T>
+constexpr T bswap(T n) noexcept
+{
+    return detail::bswapInt<T>(n);
+}
+
+template <typename T>
+constexpr T hton(T n) noexcept
+{
+    if constexpr (std::endian::native == std::endian::big)
+    {
+        return n;
+    }
+    else if constexpr (std::endian::native == std::endian::little)
+    {
+        return bswap(n);
+    }
+    else
+    {
+        static_assert(std::is_same_v<T, void>);
+    }
+}
+
+template <typename T>
+constexpr T ntoh(T n) noexcept
+{
+    return hton(n);
+}
+
+namespace detail
+{
+
 template <typename T>
 constexpr bool vcontains() noexcept
 {