xref: /openbmc/phosphor-networkd/src/types.hpp (revision 454a0dee)
11bbe3d1eSWilliam A. Kennington III #pragma once
2bb0eaccbSWilliam A. Kennington III #include <fmt/core.h>
3bb0eaccbSWilliam A. Kennington III #include <net/ethernet.h>
41bbe3d1eSWilliam A. Kennington III #include <netinet/in.h>
51bbe3d1eSWilliam A. Kennington III 
6bb0eaccbSWilliam A. Kennington III #include <algorithm>
7bb0eaccbSWilliam A. Kennington III #include <array>
81bbe3d1eSWilliam A. Kennington III #include <chrono>
971de63a2SWilliam A. Kennington III #include <numeric>
101bbe3d1eSWilliam A. Kennington III #include <sdeventplus/clock.hpp>
111bbe3d1eSWilliam A. Kennington III #include <sdeventplus/utility/timer.hpp>
121bbe3d1eSWilliam A. Kennington III #include <string>
13bb0eaccbSWilliam A. Kennington III #include <string_view>
14bb0eaccbSWilliam A. Kennington III #include <type_traits>
15dd9ef815SWilliam A. Kennington III #include <unordered_map>
16f7dce2e8SWilly Tu #include <unordered_set>
171bbe3d1eSWilliam A. Kennington III #include <variant>
181bbe3d1eSWilliam A. Kennington III 
19*454a0deeSWilliam A. Kennington III constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
20*454a0deeSWilliam A. Kennington III {
21*454a0deeSWilliam A. Kennington III     return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
22*454a0deeSWilliam A. Kennington III                       rhs.ether_addr_octet);
23*454a0deeSWilliam A. Kennington III }
24*454a0deeSWilliam A. Kennington III 
25*454a0deeSWilliam A. Kennington III constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
26*454a0deeSWilliam A. Kennington III {
27*454a0deeSWilliam A. Kennington III     return lhs.s_addr == rhs.s_addr;
28*454a0deeSWilliam A. Kennington III }
29*454a0deeSWilliam A. Kennington III 
30*454a0deeSWilliam A. Kennington III constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
31*454a0deeSWilliam A. Kennington III {
32*454a0deeSWilliam A. Kennington III     return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
33*454a0deeSWilliam A. Kennington III }
34*454a0deeSWilliam A. Kennington III 
351bbe3d1eSWilliam A. Kennington III namespace phosphor
361bbe3d1eSWilliam A. Kennington III {
371bbe3d1eSWilliam A. Kennington III namespace network
381bbe3d1eSWilliam A. Kennington III {
391bbe3d1eSWilliam A. Kennington III 
401bbe3d1eSWilliam A. Kennington III using namespace std::chrono_literals;
411bbe3d1eSWilliam A. Kennington III 
42c7cf25f7SWilliam A. Kennington III // wait for three seconds before reloading systemd-networkd
43c7cf25f7SWilliam A. Kennington III constexpr auto reloadTimeout = 3s;
441bbe3d1eSWilliam A. Kennington III 
45d41db383SWilliam A. Kennington III // refresh the objets after four seconds as network
46d41db383SWilliam A. Kennington III // configuration takes 3-4 sec to reconfigure at most.
47d41db383SWilliam A. Kennington III constexpr auto refreshTimeout = 4s;
481bbe3d1eSWilliam A. Kennington III 
491bbe3d1eSWilliam A. Kennington III // Byte representations for common address types in network byte order
50bb0eaccbSWilliam A. Kennington III using InAddrAny = std::variant<in_addr, in6_addr>;
51b9d7cbacSWilliam A. Kennington III class IfAddr
52b9d7cbacSWilliam A. Kennington III {
53b9d7cbacSWilliam A. Kennington III   private:
54b9d7cbacSWilliam A. Kennington III     InAddrAny addr;
55b9d7cbacSWilliam A. Kennington III     uint8_t pfx;
56b9d7cbacSWilliam A. Kennington III 
57b9d7cbacSWilliam A. Kennington III     static void invalidPfx(uint8_t pfx);
58b9d7cbacSWilliam A. Kennington III 
59b9d7cbacSWilliam A. Kennington III   public:
60b9d7cbacSWilliam A. Kennington III     constexpr IfAddr() : addr({}), pfx(0)
61b9d7cbacSWilliam A. Kennington III     {
62b9d7cbacSWilliam A. Kennington III     }
63b9d7cbacSWilliam A. Kennington III 
64b9d7cbacSWilliam A. Kennington III     constexpr IfAddr(InAddrAny addr, uint8_t pfx) : addr(addr), pfx(pfx)
65b9d7cbacSWilliam A. Kennington III     {
66b9d7cbacSWilliam A. Kennington III         std::visit(
67b9d7cbacSWilliam A. Kennington III             [pfx](auto v) {
68b9d7cbacSWilliam A. Kennington III                 if (sizeof(v) * 8 < pfx)
69b9d7cbacSWilliam A. Kennington III                 {
70b9d7cbacSWilliam A. Kennington III                     invalidPfx(pfx);
71b9d7cbacSWilliam A. Kennington III                 }
72b9d7cbacSWilliam A. Kennington III             },
73b9d7cbacSWilliam A. Kennington III             addr);
74b9d7cbacSWilliam A. Kennington III     }
75b9d7cbacSWilliam A. Kennington III 
76b9d7cbacSWilliam A. Kennington III     constexpr auto getAddr() const
77b9d7cbacSWilliam A. Kennington III     {
78b9d7cbacSWilliam A. Kennington III         return addr;
79b9d7cbacSWilliam A. Kennington III     }
80b9d7cbacSWilliam A. Kennington III 
81b9d7cbacSWilliam A. Kennington III     constexpr auto getPfx() const
82b9d7cbacSWilliam A. Kennington III     {
83b9d7cbacSWilliam A. Kennington III         return pfx;
84b9d7cbacSWilliam A. Kennington III     }
85b9d7cbacSWilliam A. Kennington III 
86b9d7cbacSWilliam A. Kennington III     constexpr bool operator==(phosphor::network::IfAddr rhs) const noexcept
87b9d7cbacSWilliam A. Kennington III     {
88b9d7cbacSWilliam A. Kennington III         return addr == rhs.addr && pfx == rhs.pfx;
89b9d7cbacSWilliam A. Kennington III     }
90b9d7cbacSWilliam A. Kennington III };
911bbe3d1eSWilliam A. Kennington III 
921bbe3d1eSWilliam A. Kennington III using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
931bbe3d1eSWilliam A. Kennington III 
94*454a0deeSWilliam A. Kennington III /** @class InterfaceInfo
95*454a0deeSWilliam A. Kennington III  *  @brief Information about interfaces from the kernel
96*454a0deeSWilliam A. Kennington III  */
97*454a0deeSWilliam A. Kennington III struct InterfaceInfo
98*454a0deeSWilliam A. Kennington III {
99*454a0deeSWilliam A. Kennington III     unsigned idx;
100*454a0deeSWilliam A. Kennington III     unsigned flags;
101*454a0deeSWilliam A. Kennington III     std::optional<std::string> name = std::nullopt;
102*454a0deeSWilliam A. Kennington III     std::optional<ether_addr> mac = std::nullopt;
103*454a0deeSWilliam A. Kennington III     std::optional<unsigned> mtu = std::nullopt;
104*454a0deeSWilliam A. Kennington III     std::optional<unsigned> parent_idx = std::nullopt;
105*454a0deeSWilliam A. Kennington III     std::optional<std::string> kind = std::nullopt;
106*454a0deeSWilliam A. Kennington III     std::optional<uint16_t> vlan_id = std::nullopt;
107*454a0deeSWilliam A. Kennington III 
108*454a0deeSWilliam A. Kennington III     constexpr bool operator==(const InterfaceInfo& rhs) const noexcept
109*454a0deeSWilliam A. Kennington III     {
110*454a0deeSWilliam A. Kennington III         return idx == rhs.idx && flags == rhs.flags && name == rhs.name &&
111*454a0deeSWilliam A. Kennington III                mac == rhs.mac && mtu == rhs.mtu &&
112*454a0deeSWilliam A. Kennington III                parent_idx == rhs.parent_idx && kind == rhs.kind &&
113*454a0deeSWilliam A. Kennington III                vlan_id == rhs.vlan_id;
114*454a0deeSWilliam A. Kennington III     }
115*454a0deeSWilliam A. Kennington III };
116*454a0deeSWilliam A. Kennington III 
1176a92363eSWilliam A. Kennington III /** @class AddressInfo
1186a92363eSWilliam A. Kennington III  *  @brief Information about a addresses from the kernel
1196a92363eSWilliam A. Kennington III  */
1206a92363eSWilliam A. Kennington III struct AddressInfo
1216a92363eSWilliam A. Kennington III {
1226a92363eSWilliam A. Kennington III     unsigned ifidx;
1236a92363eSWilliam A. Kennington III     IfAddr ifaddr;
1246a92363eSWilliam A. Kennington III     uint8_t scope;
1256a92363eSWilliam A. Kennington III     uint32_t flags;
126*454a0deeSWilliam A. Kennington III 
127*454a0deeSWilliam A. Kennington III     constexpr bool operator==(const AddressInfo& rhs) const noexcept
128*454a0deeSWilliam A. Kennington III     {
129*454a0deeSWilliam A. Kennington III         return ifidx == rhs.ifidx && ifaddr == rhs.ifaddr &&
130*454a0deeSWilliam A. Kennington III                scope == rhs.scope && flags == rhs.flags;
131*454a0deeSWilliam A. Kennington III     }
1326a92363eSWilliam A. Kennington III };
1336a92363eSWilliam A. Kennington III 
134a8426902SWilliam A. Kennington III /** @class NeighborInfo
135a8426902SWilliam A. Kennington III  *  @brief Information about a neighbor from the kernel
136a8426902SWilliam A. Kennington III  */
137a8426902SWilliam A. Kennington III struct NeighborInfo
138a8426902SWilliam A. Kennington III {
139a8426902SWilliam A. Kennington III     unsigned ifidx;
140*454a0deeSWilliam A. Kennington III     uint16_t state;
141a8426902SWilliam A. Kennington III     InAddrAny addr;
142a8426902SWilliam A. Kennington III     std::optional<ether_addr> mac;
143*454a0deeSWilliam A. Kennington III 
144*454a0deeSWilliam A. Kennington III     constexpr bool operator==(const NeighborInfo& rhs) const noexcept
145*454a0deeSWilliam A. Kennington III     {
146*454a0deeSWilliam A. Kennington III         return ifidx == rhs.ifidx && state == rhs.state && addr == rhs.addr &&
147*454a0deeSWilliam A. Kennington III                mac == rhs.mac;
148*454a0deeSWilliam A. Kennington III     }
149a8426902SWilliam A. Kennington III };
150a8426902SWilliam A. Kennington III 
151dd9ef815SWilliam A. Kennington III struct string_hash : public std::hash<std::string_view>
152dd9ef815SWilliam A. Kennington III {
153dd9ef815SWilliam A. Kennington III     using is_transparent = void;
154dd9ef815SWilliam A. Kennington III };
155dd9ef815SWilliam A. Kennington III template <typename V>
156dd9ef815SWilliam A. Kennington III using string_umap =
157dd9ef815SWilliam A. Kennington III     std::unordered_map<std::string, V, string_hash, std::equal_to<>>;
15896444795SWilliam A. Kennington III using string_uset =
15996444795SWilliam A. Kennington III     std::unordered_set<std::string, string_hash, std::equal_to<>>;
160dd9ef815SWilliam A. Kennington III 
1613e471c5fSWilliam A. Kennington III constexpr std::size_t hash_multi() noexcept
162991a8e81SWilliam A. Kennington III {
163991a8e81SWilliam A. Kennington III     return 0;
164991a8e81SWilliam A. Kennington III }
165991a8e81SWilliam A. Kennington III 
166991a8e81SWilliam A. Kennington III template <typename T, typename... Args>
167becda1aaSWilliam A. Kennington III constexpr std::size_t hash_multi(const T& v, const Args&... args) noexcept
168991a8e81SWilliam A. Kennington III {
169991a8e81SWilliam A. Kennington III     const std::size_t seed = hash_multi(args...);
170991a8e81SWilliam A. Kennington III     return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
171991a8e81SWilliam A. Kennington III }
172991a8e81SWilliam A. Kennington III 
173bb0eaccbSWilliam A. Kennington III namespace detail
174bb0eaccbSWilliam A. Kennington III {
175bb0eaccbSWilliam A. Kennington III 
17671de63a2SWilliam A. Kennington III template <typename T, uint8_t size = sizeof(T)>
17771de63a2SWilliam A. Kennington III struct BswapAlign
17871de63a2SWilliam A. Kennington III {
17971de63a2SWilliam A. Kennington III     using type = T;
18071de63a2SWilliam A. Kennington III };
18171de63a2SWilliam A. Kennington III 
18271de63a2SWilliam A. Kennington III template <typename T>
18371de63a2SWilliam A. Kennington III struct BswapAlign<T, 2>
18471de63a2SWilliam A. Kennington III {
18571de63a2SWilliam A. Kennington III     using type alignas(uint16_t) = T;
18671de63a2SWilliam A. Kennington III };
18771de63a2SWilliam A. Kennington III 
18871de63a2SWilliam A. Kennington III template <typename T>
18971de63a2SWilliam A. Kennington III struct BswapAlign<T, 4>
19071de63a2SWilliam A. Kennington III {
19171de63a2SWilliam A. Kennington III     using type alignas(uint32_t) = T;
19271de63a2SWilliam A. Kennington III };
19371de63a2SWilliam A. Kennington III 
19471de63a2SWilliam A. Kennington III template <typename T>
19571de63a2SWilliam A. Kennington III struct BswapAlign<T, 8>
19671de63a2SWilliam A. Kennington III {
19771de63a2SWilliam A. Kennington III     using type alignas(uint64_t) = T;
19871de63a2SWilliam A. Kennington III };
19971de63a2SWilliam A. Kennington III 
20071de63a2SWilliam A. Kennington III template <typename T>
20171de63a2SWilliam A. Kennington III constexpr T bswapInt(typename BswapAlign<T>::type n) noexcept
20271de63a2SWilliam A. Kennington III {
20371de63a2SWilliam A. Kennington III     static_assert(std::is_trivially_copyable_v<T>);
20471de63a2SWilliam A. Kennington III     if constexpr (sizeof(T) == 2)
20571de63a2SWilliam A. Kennington III     {
20671de63a2SWilliam A. Kennington III         reinterpret_cast<uint16_t&>(n) =
20771de63a2SWilliam A. Kennington III             __builtin_bswap16(reinterpret_cast<uint16_t&>(n));
20871de63a2SWilliam A. Kennington III     }
20971de63a2SWilliam A. Kennington III     else if constexpr (sizeof(T) == 4)
21071de63a2SWilliam A. Kennington III     {
21171de63a2SWilliam A. Kennington III         reinterpret_cast<uint32_t&>(n) =
21271de63a2SWilliam A. Kennington III             __builtin_bswap32(reinterpret_cast<uint32_t&>(n));
21371de63a2SWilliam A. Kennington III     }
21471de63a2SWilliam A. Kennington III     else if constexpr (sizeof(T) == 8)
21571de63a2SWilliam A. Kennington III     {
21671de63a2SWilliam A. Kennington III         reinterpret_cast<uint64_t&>(n) =
21771de63a2SWilliam A. Kennington III             __builtin_bswap64(reinterpret_cast<uint64_t&>(n));
21871de63a2SWilliam A. Kennington III     }
21971de63a2SWilliam A. Kennington III     else
22071de63a2SWilliam A. Kennington III     {
22171de63a2SWilliam A. Kennington III         auto b = reinterpret_cast<std::byte*>(&n);
22271de63a2SWilliam A. Kennington III         std::reverse(b, b + sizeof(n));
22371de63a2SWilliam A. Kennington III     }
22471de63a2SWilliam A. Kennington III     return n;
22571de63a2SWilliam A. Kennington III }
22671de63a2SWilliam A. Kennington III 
22771de63a2SWilliam A. Kennington III } // namespace detail
22871de63a2SWilliam A. Kennington III 
22971de63a2SWilliam A. Kennington III template <typename T>
23071de63a2SWilliam A. Kennington III constexpr T bswap(T n) noexcept
23171de63a2SWilliam A. Kennington III {
23271de63a2SWilliam A. Kennington III     return detail::bswapInt<T>(n);
23371de63a2SWilliam A. Kennington III }
23471de63a2SWilliam A. Kennington III 
23571de63a2SWilliam A. Kennington III template <typename T>
23671de63a2SWilliam A. Kennington III constexpr T hton(T n) noexcept
23771de63a2SWilliam A. Kennington III {
23871de63a2SWilliam A. Kennington III     if constexpr (std::endian::native == std::endian::big)
23971de63a2SWilliam A. Kennington III     {
24071de63a2SWilliam A. Kennington III         return n;
24171de63a2SWilliam A. Kennington III     }
24271de63a2SWilliam A. Kennington III     else if constexpr (std::endian::native == std::endian::little)
24371de63a2SWilliam A. Kennington III     {
24471de63a2SWilliam A. Kennington III         return bswap(n);
24571de63a2SWilliam A. Kennington III     }
24671de63a2SWilliam A. Kennington III     else
24771de63a2SWilliam A. Kennington III     {
24871de63a2SWilliam A. Kennington III         static_assert(std::is_same_v<T, void>);
24971de63a2SWilliam A. Kennington III     }
25071de63a2SWilliam A. Kennington III }
25171de63a2SWilliam A. Kennington III 
25271de63a2SWilliam A. Kennington III template <typename T>
25371de63a2SWilliam A. Kennington III constexpr T ntoh(T n) noexcept
25471de63a2SWilliam A. Kennington III {
25571de63a2SWilliam A. Kennington III     return hton(n);
25671de63a2SWilliam A. Kennington III }
25771de63a2SWilliam A. Kennington III 
25871de63a2SWilliam A. Kennington III namespace detail
25971de63a2SWilliam A. Kennington III {
260238ef992SWilliam A. Kennington III inline constexpr auto charLookup = []() {
261238ef992SWilliam A. Kennington III     std::array<int8_t, 256> ret;
262238ef992SWilliam A. Kennington III     std::fill(ret.begin(), ret.end(), -1);
263238ef992SWilliam A. Kennington III     for (int8_t i = 0; i < 10; ++i)
264238ef992SWilliam A. Kennington III     {
265238ef992SWilliam A. Kennington III         ret[i + '0'] = i;
266238ef992SWilliam A. Kennington III     }
267238ef992SWilliam A. Kennington III     for (int8_t i = 0; i < 26; ++i)
268238ef992SWilliam A. Kennington III     {
269238ef992SWilliam A. Kennington III         ret[i + 'A'] = i + 10;
270238ef992SWilliam A. Kennington III         ret[i + 'a'] = i + 10;
271238ef992SWilliam A. Kennington III     }
272238ef992SWilliam A. Kennington III     return ret;
273238ef992SWilliam A. Kennington III }();
274dd7c7b34SWilliam A. Kennington III inline constexpr auto intLookup = []() {
275dd7c7b34SWilliam A. Kennington III     std::array<char, 36> ret;
276dd7c7b34SWilliam A. Kennington III     for (int8_t i = 0; i < 10; ++i)
277dd7c7b34SWilliam A. Kennington III     {
278dd7c7b34SWilliam A. Kennington III         ret[i] = i + '0';
279238ef992SWilliam A. Kennington III     }
280dd7c7b34SWilliam A. Kennington III     for (int8_t i = 0; i < 26; ++i)
281dd7c7b34SWilliam A. Kennington III     {
282dd7c7b34SWilliam A. Kennington III         ret[i + 10] = i + 'a';
283dd7c7b34SWilliam A. Kennington III     }
284dd7c7b34SWilliam A. Kennington III     return ret;
285dd7c7b34SWilliam A. Kennington III }();
286dd7c7b34SWilliam A. Kennington III } // namespace detail
287238ef992SWilliam A. Kennington III 
288238ef992SWilliam A. Kennington III template <typename T, uint8_t base>
289238ef992SWilliam A. Kennington III struct DecodeInt
290238ef992SWilliam A. Kennington III {
291238ef992SWilliam A. Kennington III     static_assert(base > 1 && base <= 36);
292238ef992SWilliam A. Kennington III     static_assert(std::is_unsigned_v<T>);
293238ef992SWilliam A. Kennington III 
294238ef992SWilliam A. Kennington III     constexpr T operator()(std::string_view str) const
295238ef992SWilliam A. Kennington III     {
296238ef992SWilliam A. Kennington III         if (str.empty())
297238ef992SWilliam A. Kennington III         {
298238ef992SWilliam A. Kennington III             throw std::invalid_argument("Empty Str");
299238ef992SWilliam A. Kennington III         }
300238ef992SWilliam A. Kennington III         constexpr auto max = std::numeric_limits<T>::max();
301238ef992SWilliam A. Kennington III         auto ret =
302238ef992SWilliam A. Kennington III             std::accumulate(str.begin(), str.end(), T{}, [&](T r, char c) {
303238ef992SWilliam A. Kennington III                 auto v = detail::charLookup[c];
304238ef992SWilliam A. Kennington III                 if (v < 0 || v >= base)
305238ef992SWilliam A. Kennington III                 {
306238ef992SWilliam A. Kennington III                     throw std::invalid_argument("Invalid numeral");
307238ef992SWilliam A. Kennington III                 }
308238ef992SWilliam A. Kennington III                 if constexpr (std::popcount(base) == 1)
309238ef992SWilliam A. Kennington III                 {
310238ef992SWilliam A. Kennington III                     constexpr auto shift = std::countr_zero(base);
311238ef992SWilliam A. Kennington III                     constexpr auto maxshift = max >> shift;
312238ef992SWilliam A. Kennington III                     if (r > maxshift)
313238ef992SWilliam A. Kennington III                     {
314238ef992SWilliam A. Kennington III                         throw std::overflow_error("Integer Decode");
315238ef992SWilliam A. Kennington III                     }
316238ef992SWilliam A. Kennington III                     return (r << shift) | v;
317238ef992SWilliam A. Kennington III                 }
318238ef992SWilliam A. Kennington III                 else
319238ef992SWilliam A. Kennington III                 {
320238ef992SWilliam A. Kennington III                     constexpr auto maxbase = max / base;
321238ef992SWilliam A. Kennington III                     if (r > maxbase)
322238ef992SWilliam A. Kennington III                     {
323238ef992SWilliam A. Kennington III                         throw std::overflow_error("Integer Decode");
324238ef992SWilliam A. Kennington III                     }
325238ef992SWilliam A. Kennington III                     r *= base;
326238ef992SWilliam A. Kennington III                     if (max - v < r)
327238ef992SWilliam A. Kennington III                     {
328238ef992SWilliam A. Kennington III                         throw std::overflow_error("Integer Decode");
329238ef992SWilliam A. Kennington III                     }
330238ef992SWilliam A. Kennington III                     return r + v;
331238ef992SWilliam A. Kennington III                 }
332238ef992SWilliam A. Kennington III             });
333238ef992SWilliam A. Kennington III         return ret;
334238ef992SWilliam A. Kennington III     }
335238ef992SWilliam A. Kennington III };
336238ef992SWilliam A. Kennington III 
337dd7c7b34SWilliam A. Kennington III template <typename T, uint8_t base>
338dd7c7b34SWilliam A. Kennington III struct EncodeInt
339dd7c7b34SWilliam A. Kennington III {
340dd7c7b34SWilliam A. Kennington III     static_assert(base > 1 && base <= 36);
341dd7c7b34SWilliam A. Kennington III     static_assert(std::is_unsigned_v<T>);
342dd7c7b34SWilliam A. Kennington III 
343dd7c7b34SWilliam A. Kennington III     static constexpr uint8_t buf_size = []() {
344dd7c7b34SWilliam A. Kennington III         T v = std::numeric_limits<T>::max();
345dd7c7b34SWilliam A. Kennington III         uint8_t i = 0;
346dd7c7b34SWilliam A. Kennington III         for (; v != 0; ++i)
347dd7c7b34SWilliam A. Kennington III         {
348dd7c7b34SWilliam A. Kennington III             v /= base;
349dd7c7b34SWilliam A. Kennington III         }
350dd7c7b34SWilliam A. Kennington III         return i;
351dd7c7b34SWilliam A. Kennington III     }();
352dd7c7b34SWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
353dd7c7b34SWilliam A. Kennington III 
354dd7c7b34SWilliam A. Kennington III     constexpr uint8_t reverseFill(char* buf, T v) const noexcept
355dd7c7b34SWilliam A. Kennington III     {
356dd7c7b34SWilliam A. Kennington III         uint8_t i = 0;
357dd7c7b34SWilliam A. Kennington III         do
358dd7c7b34SWilliam A. Kennington III         {
359dd7c7b34SWilliam A. Kennington III             if constexpr (std::popcount(base) == 1)
360dd7c7b34SWilliam A. Kennington III             {
361dd7c7b34SWilliam A. Kennington III                 buf[i++] = detail::intLookup[v & 0xf];
362dd7c7b34SWilliam A. Kennington III                 v >>= 4;
363dd7c7b34SWilliam A. Kennington III             }
364dd7c7b34SWilliam A. Kennington III             else
365dd7c7b34SWilliam A. Kennington III             {
366dd7c7b34SWilliam A. Kennington III                 buf[i++] = detail::intLookup[v % base];
367dd7c7b34SWilliam A. Kennington III                 v /= base;
368dd7c7b34SWilliam A. Kennington III             }
369dd7c7b34SWilliam A. Kennington III         } while (v > 0);
370dd7c7b34SWilliam A. Kennington III         return i;
371dd7c7b34SWilliam A. Kennington III     }
372dd7c7b34SWilliam A. Kennington III 
373dd7c7b34SWilliam A. Kennington III     constexpr char* operator()(char* buf, T v) const noexcept
374dd7c7b34SWilliam A. Kennington III     {
375dd7c7b34SWilliam A. Kennington III         uint8_t i = reverseFill(buf, v);
376dd7c7b34SWilliam A. Kennington III         std::reverse(buf, buf + i);
377dd7c7b34SWilliam A. Kennington III         return buf + i;
378dd7c7b34SWilliam A. Kennington III     }
379dd7c7b34SWilliam A. Kennington III 
380dd7c7b34SWilliam A. Kennington III     constexpr char* operator()(char* buf, T v, uint8_t min_width) const noexcept
381dd7c7b34SWilliam A. Kennington III     {
382dd7c7b34SWilliam A. Kennington III         uint8_t i = reverseFill(buf, v);
383dd7c7b34SWilliam A. Kennington III         auto end = buf + std::max(i, min_width);
384dd7c7b34SWilliam A. Kennington III         std::fill(buf + i, end, '0');
385dd7c7b34SWilliam A. Kennington III         std::reverse(buf, end);
386dd7c7b34SWilliam A. Kennington III         return end;
387dd7c7b34SWilliam A. Kennington III     }
388dd7c7b34SWilliam A. Kennington III };
389dd7c7b34SWilliam A. Kennington III 
390b01d08fdSWilliam A. Kennington III template <typename T>
391b01d08fdSWilliam A. Kennington III struct ToAddr
392b01d08fdSWilliam A. Kennington III {
393b01d08fdSWilliam A. Kennington III };
394b01d08fdSWilliam A. Kennington III 
395b01d08fdSWilliam A. Kennington III template <>
396b01d08fdSWilliam A. Kennington III struct ToAddr<ether_addr>
397b01d08fdSWilliam A. Kennington III {
398b01d08fdSWilliam A. Kennington III     constexpr ether_addr operator()(std::string_view str) const
399b01d08fdSWilliam A. Kennington III     {
400b01d08fdSWilliam A. Kennington III         constexpr DecodeInt<uint8_t, 16> di;
401b01d08fdSWilliam A. Kennington III         ether_addr ret;
402b01d08fdSWilliam A. Kennington III         if (str.size() == 12 && str.find(":") == str.npos)
403b01d08fdSWilliam A. Kennington III         {
404b01d08fdSWilliam A. Kennington III             for (size_t i = 0; i < 6; ++i)
405b01d08fdSWilliam A. Kennington III             {
406b01d08fdSWilliam A. Kennington III                 ret.ether_addr_octet[i] = di(str.substr(i * 2, 2));
407b01d08fdSWilliam A. Kennington III             }
408b01d08fdSWilliam A. Kennington III         }
409b01d08fdSWilliam A. Kennington III         else
410b01d08fdSWilliam A. Kennington III         {
411b01d08fdSWilliam A. Kennington III             for (size_t i = 0; i < 5; ++i)
412b01d08fdSWilliam A. Kennington III             {
413b01d08fdSWilliam A. Kennington III                 auto loc = str.find(":");
414b01d08fdSWilliam A. Kennington III                 ret.ether_addr_octet[i] = di(str.substr(0, loc));
415b01d08fdSWilliam A. Kennington III                 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
416b01d08fdSWilliam A. Kennington III                 if (str.empty())
417b01d08fdSWilliam A. Kennington III                 {
418b01d08fdSWilliam A. Kennington III                     throw std::invalid_argument("Missing mac data");
419b01d08fdSWilliam A. Kennington III                 }
420b01d08fdSWilliam A. Kennington III             }
421b01d08fdSWilliam A. Kennington III             ret.ether_addr_octet[5] = di(str);
422b01d08fdSWilliam A. Kennington III         }
423b01d08fdSWilliam A. Kennington III         return ret;
424b01d08fdSWilliam A. Kennington III     }
425b01d08fdSWilliam A. Kennington III };
426b01d08fdSWilliam A. Kennington III 
427df1178e0SWilliam A. Kennington III template <>
428df1178e0SWilliam A. Kennington III struct ToAddr<in_addr>
429df1178e0SWilliam A. Kennington III {
430df1178e0SWilliam A. Kennington III     constexpr in_addr operator()(std::string_view str) const
431df1178e0SWilliam A. Kennington III     {
432df1178e0SWilliam A. Kennington III         constexpr DecodeInt<uint8_t, 10> di;
433df1178e0SWilliam A. Kennington III         uint32_t addr = {};
434df1178e0SWilliam A. Kennington III         for (size_t i = 0; i < 3; ++i)
435df1178e0SWilliam A. Kennington III         {
436df1178e0SWilliam A. Kennington III             auto loc = str.find(".");
437df1178e0SWilliam A. Kennington III             addr |= di(str.substr(0, loc));
438df1178e0SWilliam A. Kennington III             addr <<= 8;
439df1178e0SWilliam A. Kennington III             str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
440df1178e0SWilliam A. Kennington III             if (str.empty())
441df1178e0SWilliam A. Kennington III             {
442df1178e0SWilliam A. Kennington III                 throw std::invalid_argument("Missing addr data");
443df1178e0SWilliam A. Kennington III             }
444df1178e0SWilliam A. Kennington III         }
445df1178e0SWilliam A. Kennington III         addr |= di(str);
446df1178e0SWilliam A. Kennington III         return {hton(addr)};
447df1178e0SWilliam A. Kennington III     }
448df1178e0SWilliam A. Kennington III };
449df1178e0SWilliam A. Kennington III 
450ec496a86SWilliam A. Kennington III template <>
451ec496a86SWilliam A. Kennington III struct ToAddr<in6_addr>
452ec496a86SWilliam A. Kennington III {
453ec496a86SWilliam A. Kennington III     constexpr in6_addr operator()(std::string_view str) const
454ec496a86SWilliam A. Kennington III     {
455ec496a86SWilliam A. Kennington III         constexpr DecodeInt<uint16_t, 16> di;
456ec496a86SWilliam A. Kennington III         in6_addr ret = {};
457ec496a86SWilliam A. Kennington III         size_t i = 0;
458ec496a86SWilliam A. Kennington III         while (i < 8)
459ec496a86SWilliam A. Kennington III         {
460ec496a86SWilliam A. Kennington III             auto loc = str.find(':');
461ec496a86SWilliam A. Kennington III             if (i == 6 && loc == str.npos)
462ec496a86SWilliam A. Kennington III             {
463ec496a86SWilliam A. Kennington III                 ret.s6_addr32[3] = ToAddr<in_addr>{}(str).s_addr;
464ec496a86SWilliam A. Kennington III                 return ret;
465ec496a86SWilliam A. Kennington III             }
466ec496a86SWilliam A. Kennington III             if (loc != 0 && !str.empty())
467ec496a86SWilliam A. Kennington III             {
468ec496a86SWilliam A. Kennington III                 ret.s6_addr16[i++] = hton(di(str.substr(0, loc)));
469ec496a86SWilliam A. Kennington III             }
470ec496a86SWilliam A. Kennington III             if (i < 8 && str.size() > loc + 1 && str[loc + 1] == ':')
471ec496a86SWilliam A. Kennington III             {
472ec496a86SWilliam A. Kennington III                 str.remove_prefix(loc + 2);
473ec496a86SWilliam A. Kennington III                 break;
474ec496a86SWilliam A. Kennington III             }
475ec496a86SWilliam A. Kennington III             else if (str.empty())
476ec496a86SWilliam A. Kennington III             {
477ec496a86SWilliam A. Kennington III                 throw std::invalid_argument("IPv6 Data");
478ec496a86SWilliam A. Kennington III             }
479ec496a86SWilliam A. Kennington III             str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
480ec496a86SWilliam A. Kennington III         }
481ec496a86SWilliam A. Kennington III         if (str.starts_with(':'))
482ec496a86SWilliam A. Kennington III         {
483ec496a86SWilliam A. Kennington III             throw std::invalid_argument("Extra separator");
484ec496a86SWilliam A. Kennington III         }
485ec496a86SWilliam A. Kennington III         size_t j = 7;
486ec496a86SWilliam A. Kennington III         if (!str.empty() && i < 6 && str.find('.') != str.npos)
487ec496a86SWilliam A. Kennington III         {
488ec496a86SWilliam A. Kennington III             auto loc = str.rfind(':');
489ec496a86SWilliam A. Kennington III             ret.s6_addr32[3] =
490ec496a86SWilliam A. Kennington III                 ToAddr<in_addr>{}(str.substr(loc == str.npos ? 0 : loc + 1))
491ec496a86SWilliam A. Kennington III                     .s_addr;
492ec496a86SWilliam A. Kennington III             str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
493ec496a86SWilliam A. Kennington III             j -= 2;
494ec496a86SWilliam A. Kennington III         }
495ec496a86SWilliam A. Kennington III         while (!str.empty() && j > i)
496ec496a86SWilliam A. Kennington III         {
497ec496a86SWilliam A. Kennington III             auto loc = str.rfind(':');
498ec496a86SWilliam A. Kennington III             ret.s6_addr16[j--] =
499ec496a86SWilliam A. Kennington III                 hton(di(str.substr(loc == str.npos ? 0 : loc + 1)));
500ec496a86SWilliam A. Kennington III             str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
501ec496a86SWilliam A. Kennington III         }
502ec496a86SWilliam A. Kennington III         if (!str.empty())
503ec496a86SWilliam A. Kennington III         {
504ec496a86SWilliam A. Kennington III             throw std::invalid_argument("Too much data");
505ec496a86SWilliam A. Kennington III         }
506ec496a86SWilliam A. Kennington III         return ret;
507ec496a86SWilliam A. Kennington III     }
508ec496a86SWilliam A. Kennington III };
509ec496a86SWilliam A. Kennington III 
510ead7198cSWilliam A. Kennington III template <>
511ead7198cSWilliam A. Kennington III struct ToAddr<InAddrAny>
512ead7198cSWilliam A. Kennington III {
513ead7198cSWilliam A. Kennington III     constexpr InAddrAny operator()(std::string_view str) const
514ead7198cSWilliam A. Kennington III     {
515ead7198cSWilliam A. Kennington III         if (str.find(':') == str.npos)
516ead7198cSWilliam A. Kennington III         {
517ead7198cSWilliam A. Kennington III             return ToAddr<in_addr>{}(str);
518ead7198cSWilliam A. Kennington III         }
519ead7198cSWilliam A. Kennington III         return ToAddr<in6_addr>{}(str);
520ead7198cSWilliam A. Kennington III     }
521ead7198cSWilliam A. Kennington III };
522ead7198cSWilliam A. Kennington III 
523ead7198cSWilliam A. Kennington III template <>
524ead7198cSWilliam A. Kennington III struct ToAddr<IfAddr>
525ead7198cSWilliam A. Kennington III {
526ead7198cSWilliam A. Kennington III     constexpr IfAddr operator()(std::string_view str) const
527ead7198cSWilliam A. Kennington III     {
528ead7198cSWilliam A. Kennington III         auto pos = str.rfind('/');
529ead7198cSWilliam A. Kennington III         if (pos == str.npos)
530ead7198cSWilliam A. Kennington III         {
531ead7198cSWilliam A. Kennington III             throw std::invalid_argument("Invalid IfAddr");
532ead7198cSWilliam A. Kennington III         }
533ead7198cSWilliam A. Kennington III         return {ToAddr<InAddrAny>{}(str.substr(0, pos)),
534ead7198cSWilliam A. Kennington III                 DecodeInt<uint8_t, 10>{}(str.substr(pos + 1))};
535ead7198cSWilliam A. Kennington III     }
536ead7198cSWilliam A. Kennington III };
537ead7198cSWilliam A. Kennington III 
53855bdc36cSWilliam A. Kennington III template <typename T>
53955bdc36cSWilliam A. Kennington III struct ToStr
54055bdc36cSWilliam A. Kennington III {
54155bdc36cSWilliam A. Kennington III };
54255bdc36cSWilliam A. Kennington III 
54355bdc36cSWilliam A. Kennington III template <>
54455bdc36cSWilliam A. Kennington III struct ToStr<char>
54555bdc36cSWilliam A. Kennington III {
54655bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = 1;
54755bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
54855bdc36cSWilliam A. Kennington III 
54955bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, char v) const noexcept
55055bdc36cSWilliam A. Kennington III     {
55155bdc36cSWilliam A. Kennington III         buf[0] = v;
55255bdc36cSWilliam A. Kennington III         return buf + 1;
55355bdc36cSWilliam A. Kennington III     }
55455bdc36cSWilliam A. Kennington III };
55555bdc36cSWilliam A. Kennington III 
55655bdc36cSWilliam A. Kennington III template <>
55755bdc36cSWilliam A. Kennington III struct ToStr<ether_addr>
55855bdc36cSWilliam A. Kennington III {
55955bdc36cSWilliam A. Kennington III     // 6 octets * 2 hex chars + 5 separators
56055bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = 17;
56155bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
56255bdc36cSWilliam A. Kennington III 
56355bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, ether_addr v) const noexcept
56455bdc36cSWilliam A. Kennington III     {
56555bdc36cSWilliam A. Kennington III         for (char* ptr = buf + 2; ptr < buf + buf_size; ptr += 3)
56655bdc36cSWilliam A. Kennington III         {
56755bdc36cSWilliam A. Kennington III             *ptr = ':';
56855bdc36cSWilliam A. Kennington III         }
56955bdc36cSWilliam A. Kennington III         for (size_t i = 0; i < 6; ++i)
57055bdc36cSWilliam A. Kennington III         {
57155bdc36cSWilliam A. Kennington III             char* tmp = buf + i * 3;
57255bdc36cSWilliam A. Kennington III             uint8_t byte = v.ether_addr_octet[i];
57355bdc36cSWilliam A. Kennington III             EncodeInt<uint8_t, 16>{}(tmp, byte, 2);
57455bdc36cSWilliam A. Kennington III         }
57555bdc36cSWilliam A. Kennington III         return buf + buf_size;
57655bdc36cSWilliam A. Kennington III     }
57755bdc36cSWilliam A. Kennington III };
57855bdc36cSWilliam A. Kennington III 
57955bdc36cSWilliam A. Kennington III template <>
58055bdc36cSWilliam A. Kennington III struct ToStr<in_addr>
58155bdc36cSWilliam A. Kennington III {
58255bdc36cSWilliam A. Kennington III     // 4 octets * 3 dec chars + 3 separators
58355bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = 15;
58455bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
58555bdc36cSWilliam A. Kennington III 
58655bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, in_addr v) const noexcept
58755bdc36cSWilliam A. Kennington III     {
58855bdc36cSWilliam A. Kennington III         auto n = bswap(ntoh(v.s_addr));
58955bdc36cSWilliam A. Kennington III         for (size_t i = 0; i < 3; ++i)
59055bdc36cSWilliam A. Kennington III         {
59155bdc36cSWilliam A. Kennington III             buf = ToStr<char>{}(EncodeInt<uint8_t, 10>{}(buf, n & 0xff), '.');
59255bdc36cSWilliam A. Kennington III             n >>= 8;
59355bdc36cSWilliam A. Kennington III         }
59455bdc36cSWilliam A. Kennington III         return EncodeInt<uint8_t, 10>{}(buf, n & 0xff);
59555bdc36cSWilliam A. Kennington III     }
59655bdc36cSWilliam A. Kennington III };
59755bdc36cSWilliam A. Kennington III 
59855bdc36cSWilliam A. Kennington III template <>
59955bdc36cSWilliam A. Kennington III struct ToStr<in6_addr>
60055bdc36cSWilliam A. Kennington III {
60155bdc36cSWilliam A. Kennington III     // 8 hextets * 4 hex chars + 7 separators
60255bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = 39;
60355bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
60455bdc36cSWilliam A. Kennington III 
60555bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, in6_addr v) const noexcept
60655bdc36cSWilliam A. Kennington III     {
60755bdc36cSWilliam A. Kennington III         // IPv4 in IPv6 Addr
60855bdc36cSWilliam A. Kennington III         if (v.s6_addr32[0] == 0 && v.s6_addr32[1] == 0 &&
60955bdc36cSWilliam A. Kennington III             v.s6_addr32[2] == hton(uint32_t(0xffff)))
61055bdc36cSWilliam A. Kennington III         {
61155bdc36cSWilliam A. Kennington III             constexpr auto prefix = std::string_view("::ffff:");
61255bdc36cSWilliam A. Kennington III             return ToStr<in_addr>{}(
61355bdc36cSWilliam A. Kennington III                 std::copy(prefix.begin(), prefix.end(), buf), {v.s6_addr32[3]});
61455bdc36cSWilliam A. Kennington III         }
61555bdc36cSWilliam A. Kennington III 
61655bdc36cSWilliam A. Kennington III         size_t skip_start = 0;
61755bdc36cSWilliam A. Kennington III         size_t skip_size = 0;
61855bdc36cSWilliam A. Kennington III         {
61955bdc36cSWilliam A. Kennington III             size_t new_start = 0;
62055bdc36cSWilliam A. Kennington III             size_t new_size = 0;
62155bdc36cSWilliam A. Kennington III             for (size_t i = 0; i < 9; ++i)
62255bdc36cSWilliam A. Kennington III             {
62355bdc36cSWilliam A. Kennington III                 if (i < 8 && v.s6_addr16[i] == 0)
62455bdc36cSWilliam A. Kennington III                 {
62555bdc36cSWilliam A. Kennington III                     if (new_start + new_size == i)
62655bdc36cSWilliam A. Kennington III                     {
62755bdc36cSWilliam A. Kennington III                         new_size++;
62855bdc36cSWilliam A. Kennington III                     }
62955bdc36cSWilliam A. Kennington III                     else
63055bdc36cSWilliam A. Kennington III                     {
63155bdc36cSWilliam A. Kennington III                         new_start = i;
63255bdc36cSWilliam A. Kennington III                         new_size = 1;
63355bdc36cSWilliam A. Kennington III                     }
63455bdc36cSWilliam A. Kennington III                 }
63555bdc36cSWilliam A. Kennington III                 else if (new_start + new_size == i && new_size > skip_size)
63655bdc36cSWilliam A. Kennington III                 {
63755bdc36cSWilliam A. Kennington III                     skip_start = new_start;
63855bdc36cSWilliam A. Kennington III                     skip_size = new_size;
63955bdc36cSWilliam A. Kennington III                 }
64055bdc36cSWilliam A. Kennington III             }
64155bdc36cSWilliam A. Kennington III         }
64255bdc36cSWilliam A. Kennington III         for (size_t i = 0; i < 8; ++i)
64355bdc36cSWilliam A. Kennington III         {
64455bdc36cSWilliam A. Kennington III             if (i == skip_start && skip_size > 1)
64555bdc36cSWilliam A. Kennington III             {
64655bdc36cSWilliam A. Kennington III                 if (i == 0)
64755bdc36cSWilliam A. Kennington III                 {
64855bdc36cSWilliam A. Kennington III                     *(buf++) = ':';
64955bdc36cSWilliam A. Kennington III                 }
65055bdc36cSWilliam A. Kennington III                 *(buf++) = ':';
65155bdc36cSWilliam A. Kennington III                 i += skip_size - 1;
65255bdc36cSWilliam A. Kennington III                 continue;
65355bdc36cSWilliam A. Kennington III             }
65455bdc36cSWilliam A. Kennington III             buf = EncodeInt<uint16_t, 16>{}(buf, ntoh(v.s6_addr16[i]));
65555bdc36cSWilliam A. Kennington III             if (i < 7)
65655bdc36cSWilliam A. Kennington III             {
65755bdc36cSWilliam A. Kennington III                 *(buf++) = ':';
65855bdc36cSWilliam A. Kennington III             }
65955bdc36cSWilliam A. Kennington III         }
66055bdc36cSWilliam A. Kennington III         return buf;
66155bdc36cSWilliam A. Kennington III     }
66255bdc36cSWilliam A. Kennington III };
66355bdc36cSWilliam A. Kennington III 
66455bdc36cSWilliam A. Kennington III template <>
66555bdc36cSWilliam A. Kennington III struct ToStr<InAddrAny>
66655bdc36cSWilliam A. Kennington III {
66755bdc36cSWilliam A. Kennington III     // IPv6 is the bigger of the addrs
66855bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = ToStr<in6_addr>::buf_size;
66955bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
67055bdc36cSWilliam A. Kennington III 
67155bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, InAddrAny v) const noexcept
67255bdc36cSWilliam A. Kennington III     {
67355bdc36cSWilliam A. Kennington III         return std::visit([=](auto v) { return ToStr<decltype(v)>{}(buf, v); },
67455bdc36cSWilliam A. Kennington III                           v);
67555bdc36cSWilliam A. Kennington III     }
67655bdc36cSWilliam A. Kennington III };
67755bdc36cSWilliam A. Kennington III 
67855bdc36cSWilliam A. Kennington III template <>
67955bdc36cSWilliam A. Kennington III struct ToStr<IfAddr>
68055bdc36cSWilliam A. Kennington III {
68155bdc36cSWilliam A. Kennington III     // InAddrAny + sep + 3 prefix chars
68255bdc36cSWilliam A. Kennington III     static constexpr uint8_t buf_size = ToStr<InAddrAny>::buf_size + 4;
68355bdc36cSWilliam A. Kennington III     using buf_type = std::array<char, buf_size>;
68455bdc36cSWilliam A. Kennington III 
68555bdc36cSWilliam A. Kennington III     constexpr char* operator()(char* buf, IfAddr v) const noexcept
68655bdc36cSWilliam A. Kennington III     {
68755bdc36cSWilliam A. Kennington III         buf = ToStr<InAddrAny>{}(buf, v.getAddr());
68855bdc36cSWilliam A. Kennington III         buf = ToStr<char>{}(buf, '/');
68955bdc36cSWilliam A. Kennington III         return EncodeInt<uint8_t, 10>{}(buf, v.getPfx());
69055bdc36cSWilliam A. Kennington III     }
69155bdc36cSWilliam A. Kennington III };
69255bdc36cSWilliam A. Kennington III 
693238ef992SWilliam A. Kennington III namespace detail
694238ef992SWilliam A. Kennington III {
69571de63a2SWilliam A. Kennington III 
696bb0eaccbSWilliam A. Kennington III template <typename T>
697bb0eaccbSWilliam A. Kennington III constexpr bool vcontains() noexcept
698bb0eaccbSWilliam A. Kennington III {
699bb0eaccbSWilliam A. Kennington III     return false;
700bb0eaccbSWilliam A. Kennington III }
701bb0eaccbSWilliam A. Kennington III 
702bb0eaccbSWilliam A. Kennington III template <typename T, typename V, typename... Vs>
703bb0eaccbSWilliam A. Kennington III constexpr bool vcontains() noexcept
704bb0eaccbSWilliam A. Kennington III {
705bb0eaccbSWilliam A. Kennington III     return vcontains<T, Vs...>() || std::is_same_v<T, V>;
706bb0eaccbSWilliam A. Kennington III }
707bb0eaccbSWilliam A. Kennington III 
708bb0eaccbSWilliam A. Kennington III template <typename T, typename... Types>
709bb0eaccbSWilliam A. Kennington III constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
710bb0eaccbSWilliam A. Kennington III     veq(T t, std::variant<Types...> v) noexcept
711bb0eaccbSWilliam A. Kennington III {
712bb0eaccbSWilliam A. Kennington III     return std::visit(
713bb0eaccbSWilliam A. Kennington III         [t](auto v) {
714bb0eaccbSWilliam A. Kennington III             if constexpr (std::is_same_v<T, decltype(v)>)
715bb0eaccbSWilliam A. Kennington III             {
716bb0eaccbSWilliam A. Kennington III                 return v == t;
717bb0eaccbSWilliam A. Kennington III             }
718bb0eaccbSWilliam A. Kennington III             else
719bb0eaccbSWilliam A. Kennington III             {
720bb0eaccbSWilliam A. Kennington III                 return false;
721bb0eaccbSWilliam A. Kennington III             }
722bb0eaccbSWilliam A. Kennington III         },
723bb0eaccbSWilliam A. Kennington III         v);
724bb0eaccbSWilliam A. Kennington III }
725bb0eaccbSWilliam A. Kennington III 
726bb0eaccbSWilliam A. Kennington III template <typename T>
72755bdc36cSWilliam A. Kennington III struct ToStrBuf
728bb0eaccbSWilliam A. Kennington III {
729bb0eaccbSWilliam A. Kennington III   public:
73055bdc36cSWilliam A. Kennington III     constexpr std::string_view operator()(T v) noexcept
731bb0eaccbSWilliam A. Kennington III     {
73255bdc36cSWilliam A. Kennington III         return {buf.data(), ToStr<T>{}(buf.data(), v)};
73355bdc36cSWilliam A. Kennington III     }
734bb0eaccbSWilliam A. Kennington III 
735bb0eaccbSWilliam A. Kennington III   private:
73655bdc36cSWilliam A. Kennington III     typename ToStr<T>::buf_type buf;
737bb0eaccbSWilliam A. Kennington III };
738bb0eaccbSWilliam A. Kennington III 
73955bdc36cSWilliam A. Kennington III template <typename T>
74055bdc36cSWilliam A. Kennington III struct Format
741bb0eaccbSWilliam A. Kennington III {
742bb0eaccbSWilliam A. Kennington III   private:
743bb0eaccbSWilliam A. Kennington III     fmt::formatter<std::string_view> formatter;
744bb0eaccbSWilliam A. Kennington III 
745bb0eaccbSWilliam A. Kennington III   public:
746bb0eaccbSWilliam A. Kennington III     template <typename ParseContext>
747bb0eaccbSWilliam A. Kennington III     constexpr auto parse(ParseContext& ctx)
748bb0eaccbSWilliam A. Kennington III     {
749bb0eaccbSWilliam A. Kennington III         return ctx.begin();
750bb0eaccbSWilliam A. Kennington III     }
751bb0eaccbSWilliam A. Kennington III 
752bb0eaccbSWilliam A. Kennington III     template <typename FormatContext>
753bb0eaccbSWilliam A. Kennington III     auto format(auto v, FormatContext& ctx) const
754bb0eaccbSWilliam A. Kennington III     {
75555bdc36cSWilliam A. Kennington III         return formatter.format(ToStrBuf<T>{}(v), ctx);
756bb0eaccbSWilliam A. Kennington III     }
757bb0eaccbSWilliam A. Kennington III };
758bb0eaccbSWilliam A. Kennington III } // namespace detail
7591bbe3d1eSWilliam A. Kennington III } // namespace network
7601bbe3d1eSWilliam A. Kennington III } // namespace phosphor
7613e471c5fSWilliam A. Kennington III 
7623e471c5fSWilliam A. Kennington III template <typename... Ts>
7633e471c5fSWilliam A. Kennington III struct std::hash<std::tuple<Ts...>>
7643e471c5fSWilliam A. Kennington III {
7653e471c5fSWilliam A. Kennington III     constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
7663e471c5fSWilliam A. Kennington III     {
7673e471c5fSWilliam A. Kennington III         return std::apply(phosphor::network::hash_multi<Ts...>, t);
7683e471c5fSWilliam A. Kennington III     }
7693e471c5fSWilliam A. Kennington III };
770bb0eaccbSWilliam A. Kennington III 
771653114fcSWilliam A. Kennington III template <>
772653114fcSWilliam A. Kennington III struct std::hash<in_addr>
773653114fcSWilliam A. Kennington III {
774653114fcSWilliam A. Kennington III     std::size_t operator()(in_addr addr) const noexcept;
775653114fcSWilliam A. Kennington III };
776653114fcSWilliam A. Kennington III 
777653114fcSWilliam A. Kennington III template <>
778653114fcSWilliam A. Kennington III struct std::hash<in6_addr>
779653114fcSWilliam A. Kennington III {
780653114fcSWilliam A. Kennington III     std::size_t operator()(in6_addr addr) const noexcept;
781653114fcSWilliam A. Kennington III };
782653114fcSWilliam A. Kennington III 
783b9d7cbacSWilliam A. Kennington III template <>
784b9d7cbacSWilliam A. Kennington III struct std::hash<phosphor::network::IfAddr>
785b9d7cbacSWilliam A. Kennington III {
786b9d7cbacSWilliam A. Kennington III     std::size_t operator()(phosphor::network::IfAddr addr) const noexcept;
787b9d7cbacSWilliam A. Kennington III };
788b9d7cbacSWilliam A. Kennington III 
789bb0eaccbSWilliam A. Kennington III namespace fmt
790bb0eaccbSWilliam A. Kennington III {
791bb0eaccbSWilliam A. Kennington III template <>
79255bdc36cSWilliam A. Kennington III struct formatter<ether_addr> : phosphor::network::detail::Format<ether_addr>
793bb0eaccbSWilliam A. Kennington III {
794bb0eaccbSWilliam A. Kennington III };
795bb0eaccbSWilliam A. Kennington III template <>
79655bdc36cSWilliam A. Kennington III struct formatter<in_addr> : phosphor::network::detail::Format<in_addr>
797bb0eaccbSWilliam A. Kennington III {
798bb0eaccbSWilliam A. Kennington III };
799bb0eaccbSWilliam A. Kennington III template <>
80055bdc36cSWilliam A. Kennington III struct formatter<in6_addr> : phosphor::network::detail::Format<in6_addr>
801bb0eaccbSWilliam A. Kennington III {
802bb0eaccbSWilliam A. Kennington III };
803bb0eaccbSWilliam A. Kennington III template <>
804bb0eaccbSWilliam A. Kennington III struct formatter<phosphor::network::InAddrAny>
80555bdc36cSWilliam A. Kennington III     : phosphor::network::detail::Format<phosphor::network::InAddrAny>
806bb0eaccbSWilliam A. Kennington III {
807bb0eaccbSWilliam A. Kennington III };
808b9d7cbacSWilliam A. Kennington III template <>
809b9d7cbacSWilliam A. Kennington III struct formatter<phosphor::network::IfAddr>
81055bdc36cSWilliam A. Kennington III     : phosphor::network::detail::Format<phosphor::network::IfAddr>
811b9d7cbacSWilliam A. Kennington III {
812b9d7cbacSWilliam A. Kennington III };
813bb0eaccbSWilliam A. Kennington III } // namespace fmt
814bb0eaccbSWilliam A. Kennington III 
815bb0eaccbSWilliam A. Kennington III namespace std
816bb0eaccbSWilliam A. Kennington III {
817bb0eaccbSWilliam A. Kennington III string to_string(ether_addr value);
818bb0eaccbSWilliam A. Kennington III string to_string(in_addr value);
819bb0eaccbSWilliam A. Kennington III string to_string(in6_addr value);
820bb0eaccbSWilliam A. Kennington III string to_string(phosphor::network::InAddrAny value);
821b9d7cbacSWilliam A. Kennington III string to_string(phosphor::network::IfAddr value);
822bb0eaccbSWilliam A. Kennington III } // namespace std
823bb0eaccbSWilliam A. Kennington III 
824bb0eaccbSWilliam A. Kennington III template <typename T>
825bb0eaccbSWilliam A. Kennington III constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
826bb0eaccbSWilliam A. Kennington III                            bool>
827bb0eaccbSWilliam A. Kennington III     operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
828bb0eaccbSWilliam A. Kennington III {
829bb0eaccbSWilliam A. Kennington III     return phosphor::network::detail::veq(rhs, lhs);
830bb0eaccbSWilliam A. Kennington III }
831bb0eaccbSWilliam A. Kennington III 
83286eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, ether_addr v)
833bb0eaccbSWilliam A. Kennington III {
83455bdc36cSWilliam A. Kennington III     return os << phosphor::network::detail::ToStrBuf<ether_addr>{}(v);
835bb0eaccbSWilliam A. Kennington III }
836bb0eaccbSWilliam A. Kennington III 
83786eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, in_addr v)
838bb0eaccbSWilliam A. Kennington III {
83955bdc36cSWilliam A. Kennington III     return os << phosphor::network::detail::ToStrBuf<in_addr>{}(v);
840bb0eaccbSWilliam A. Kennington III }
841bb0eaccbSWilliam A. Kennington III 
84286eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, in6_addr v)
843bb0eaccbSWilliam A. Kennington III {
84455bdc36cSWilliam A. Kennington III     return os << phosphor::network::detail::ToStrBuf<in6_addr>{}(v);
845bb0eaccbSWilliam A. Kennington III }
846bb0eaccbSWilliam A. Kennington III 
84786eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, phosphor::network::InAddrAny v)
848bb0eaccbSWilliam A. Kennington III {
84955bdc36cSWilliam A. Kennington III     phosphor::network::detail::ToStrBuf<phosphor::network::InAddrAny> tsb;
85055bdc36cSWilliam A. Kennington III     return os << tsb(v);
851bb0eaccbSWilliam A. Kennington III }
852b9d7cbacSWilliam A. Kennington III 
853b9d7cbacSWilliam A. Kennington III auto& operator<<(auto& os, phosphor::network::IfAddr v)
854b9d7cbacSWilliam A. Kennington III {
85555bdc36cSWilliam A. Kennington III     phosphor::network::detail::ToStrBuf<phosphor::network::IfAddr> tsb;
85655bdc36cSWilliam A. Kennington III     return os << tsb(v);
857b9d7cbacSWilliam A. Kennington III }
858