100.00% Lines (19/19) 100.00% Functions (7/7)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 5   // Distributed under the Boost Software License, Version 1.0. (See accompanying
6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/corosio 8   // Official repository: https://github.com/cppalliance/corosio
9   // 9   //
10   10  
11   #ifndef BOOST_COROSIO_IPV6_ADDRESS_HPP 11   #ifndef BOOST_COROSIO_IPV6_ADDRESS_HPP
12   #define BOOST_COROSIO_IPV6_ADDRESS_HPP 12   #define BOOST_COROSIO_IPV6_ADDRESS_HPP
13   13  
14   #include <boost/corosio/detail/config.hpp> 14   #include <boost/corosio/detail/config.hpp>
15   #include <boost/corosio/ipv4_address.hpp> 15   #include <boost/corosio/ipv4_address.hpp>
16   16  
17   #include <boost/capy/results.hpp> 17   #include <boost/capy/results.hpp>
18   18  
19   #include <array> 19   #include <array>
20   #include <compare> 20   #include <compare>
21   #include <cstdint> 21   #include <cstdint>
22   #include <functional> 22   #include <functional>
23   #include <iosfwd> 23   #include <iosfwd>
24   #include <string> 24   #include <string>
25   #include <string_view> 25   #include <string_view>
26   #include <system_error> 26   #include <system_error>
27   27  
28   namespace boost::corosio { 28   namespace boost::corosio {
29   29  
30   /** An IP version 6 style address. 30   /** An IP version 6 style address.
31   31  
32   Objects of this type are used to construct, 32   Objects of this type are used to construct,
33   parse, and manipulate IP version 6 addresses. 33   parse, and manipulate IP version 6 addresses.
34   34  
35   @par BNF 35   @par BNF
36   @code 36   @code
37   IPv6address = 6( h16 ":" ) ls32 37   IPv6address = 6( h16 ":" ) ls32
38   / "::" 5( h16 ":" ) ls32 38   / "::" 5( h16 ":" ) ls32
39   / [ h16 ] "::" 4( h16 ":" ) ls32 39   / [ h16 ] "::" 4( h16 ":" ) ls32
40   / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 40   / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
41   / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 41   / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
42   / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 42   / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
43   / [ *4( h16 ":" ) h16 ] "::" ls32 43   / [ *4( h16 ":" ) h16 ] "::" ls32
44   / [ *5( h16 ":" ) h16 ] "::" h16 44   / [ *5( h16 ":" ) h16 ] "::" h16
45   / [ *6( h16 ":" ) h16 ] "::" 45   / [ *6( h16 ":" ) h16 ] "::"
46   46  
47   ls32 = ( h16 ":" h16 ) / IPv4address 47   ls32 = ( h16 ":" h16 ) / IPv4address
48   ; least-significant 32 bits of address 48   ; least-significant 32 bits of address
49   49  
50   h16 = 1*4HEXDIG 50   h16 = 1*4HEXDIG
51   ; 16 bits of address represented in hexadecimal 51   ; 16 bits of address represented in hexadecimal
52   52  
53   IPv6addrz = IPv6address "%" ZoneID 53   IPv6addrz = IPv6address "%" ZoneID
54   ; rfc6874: an address qualified by its zone 54   ; rfc6874: an address qualified by its zone
55   @endcode 55   @endcode
56   56  
57   The zone accepts a strict decimal interface index on every 57   The zone accepts a strict decimal interface index on every
58   platform; where the platform names interfaces (POSIX), an 58   platform; where the platform names interfaces (POSIX), an
59   interface name maps through `if_nametoindex`. An unknown name 59   interface name maps through `if_nametoindex`. An unknown name
60   or malformed index is a parse error, never a silent zone 0. 60   or malformed index is a parse error, never a silent zone 0.
61   Formatting always emits the numeric form (`%2`). 61   Formatting always emits the numeric form (`%2`).
62   62  
63   @par Specification 63   @par Specification
64   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291" 64   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291"
65   >IP Version 6 Addressing Architecture (rfc4291)</a> 65   >IP Version 6 Addressing Architecture (rfc4291)</a>
66   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 66   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
67   >3.2.2. Host (rfc3986)</a> 67   >3.2.2. Host (rfc3986)</a>
68   68  
69   @see 69   @see
70   @ref ipv4_address, 70   @ref ipv4_address,
71   @ref make_ipv6_address 71   @ref make_ipv6_address
72   */ 72   */
73   class BOOST_COROSIO_DECL ipv6_address 73   class BOOST_COROSIO_DECL ipv6_address
74   { 74   {
75   std::array<unsigned char, 16> addr_{}; 75   std::array<unsigned char, 16> addr_{};
76   std::uint32_t scope_id_ = 0; 76   std::uint32_t scope_id_ = 0;
77   77  
78   public: 78   public:
79   /** The number of characters in the longest possible IPv6 string. 79   /** The number of characters in the longest possible IPv6 string.
80   80  
81   The longest address body is the IPv4-mapped form 81   The longest address body is the IPv4-mapped form
82   `ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255` (45 characters). A 82   `ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255` (45 characters). A
83   numeric zone suffix adds up to eleven more (`%4294967295`), for a 83   numeric zone suffix adds up to eleven more (`%4294967295`), for a
84   worst case of 56; the constant carries a little slack. 84   worst case of 56; the constant carries a little slack.
85   */ 85   */
86   static constexpr std::size_t max_str_len = 60; 86   static constexpr std::size_t max_str_len = 60;
87   87  
88   /** The type used to represent an address as an array of bytes. 88   /** The type used to represent an address as an array of bytes.
89   89  
90   Octets are stored in network byte order. 90   Octets are stored in network byte order.
91   */ 91   */
92   using bytes_type = std::array<unsigned char, 16>; 92   using bytes_type = std::array<unsigned char, 16>;
93   93  
94   /** Default constructor. 94   /** Default constructor.
95   95  
96   Constructs the unspecified address (::). 96   Constructs the unspecified address (::).
97   97  
98   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2" 98   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"
99   >2.5.2. The Unspecified Address</a> 99   >2.5.2. The Unspecified Address</a>
100   100  
101   @see 101   @see
102   @ref is_unspecified 102   @ref is_unspecified
103   */ 103   */
HITCBC 104   299623 ipv6_address() = default; 104   304777 ipv6_address() = default;
105   105  
106   /** Copy constructor. 106   /** Copy constructor.
107   */ 107   */
108   ipv6_address(ipv6_address const&) = default; 108   ipv6_address(ipv6_address const&) = default;
109   109  
110   /** Copy assignment. 110   /** Copy assignment.
111   111  
112   @return A reference to this object. 112   @return A reference to this object.
113   */ 113   */
114   ipv6_address& operator=(ipv6_address const&) = default; 114   ipv6_address& operator=(ipv6_address const&) = default;
115   115  
116   /** Construct from an array of bytes. 116   /** Construct from an array of bytes.
117   117  
118   This function constructs an address 118   This function constructs an address
119   from the array in `bytes`, which is 119   from the array in `bytes`, which is
120   interpreted in big-endian. 120   interpreted in big-endian.
121   121  
122   @param bytes The value to construct from. 122   @param bytes The value to construct from.
123   @param scope_id The zone the address belongs to, as an 123   @param scope_id The zone the address belongs to, as an
124   interface index; 0 means unscoped. 124   interface index; 0 means unscoped.
125   */ 125   */
126   explicit ipv6_address( 126   explicit ipv6_address(
127   bytes_type const& bytes, std::uint32_t scope_id = 0) noexcept; 127   bytes_type const& bytes, std::uint32_t scope_id = 0) noexcept;
128   128  
129   /** Return the zone the address belongs to. 129   /** Return the zone the address belongs to.
130   130  
131   Link-local addresses (`fe80::/10`) are unique only per network link, 131   Link-local addresses (`fe80::/10`) are unique only per network link,
132   so the address bits alone do not identify a destination. The zone — 132   so the address bits alone do not identify a destination. The zone —
133   an interface index, written with a `%` suffix in text form — 133   an interface index, written with a `%` suffix in text form —
134   disambiguates. For global addresses the zone is 0 and has no 134   disambiguates. For global addresses the zone is 0 and has no
135   meaning. 135   meaning.
136   136  
137   @return The zone as an interface index; 0 if unscoped. 137   @return The zone as an interface index; 0 if unscoped.
138   138  
139   @par Specification 139   @par Specification
140   @li <a href="https://datatracker.ietf.org/doc/html/rfc4007" 140   @li <a href="https://datatracker.ietf.org/doc/html/rfc4007"
141   >IPv6 Scoped Address Architecture (rfc4007)</a> 141   >IPv6 Scoped Address Architecture (rfc4007)</a>
142   */ 142   */
HITCBC 143   177 std::uint32_t scope_id() const noexcept 143   177 std::uint32_t scope_id() const noexcept
144   { 144   {
HITCBC 145   177 return scope_id_; 145   177 return scope_id_;
146   } 146   }
147   147  
148   /** Construct from an IPv4 address. 148   /** Construct from an IPv4 address.
149   149  
150   This function constructs an IPv6 address 150   This function constructs an IPv6 address
151   from the IPv4 address `addr`. The resulting 151   from the IPv4 address `addr`. The resulting
152   address is an IPv4-Mapped IPv6 Address. 152   address is an IPv4-Mapped IPv6 Address.
153   153  
154   @param addr The address to construct from. 154   @param addr The address to construct from.
155   155  
156   @par Specification 156   @par Specification
157   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2" 157   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
158   >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> 158   >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
159   */ 159   */
160   explicit ipv6_address(ipv4_address const& addr) noexcept; 160   explicit ipv6_address(ipv4_address const& addr) noexcept;
161   161  
162   /** Return the address as bytes, in network byte order. 162   /** Return the address as bytes, in network byte order.
163   163  
164   The 16 bytes cannot carry the zone: for a scoped address 164   The 16 bytes cannot carry the zone: for a scoped address
165   the result identifies the value only together with 165   the result identifies the value only together with
166   @ref scope_id. 166   @ref scope_id.
167   167  
168   @return The address as an array of bytes. 168   @return The address as an array of bytes.
169   */ 169   */
HITCBC 170   261 bytes_type to_bytes() const noexcept 170   261 bytes_type to_bytes() const noexcept
171   { 171   {
HITCBC 172   261 return addr_; 172   261 return addr_;
173   } 173   }
174   174  
175   /** Return the address as a string. 175   /** Return the address as a string.
176   176  
177   The returned string does not 177   The returned string does not
178   contain surrounding square brackets. 178   contain surrounding square brackets.
179   179  
180   @par Example 180   @par Example
181   @par !example to_string 181   @par !example to_string
182   182  
183   @return The address as a string. 183   @return The address as a string.
184   184  
185   @par Specification 185   @par Specification
186   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2"> 186   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
187   2.2. Text Representation of Addresses (rfc4291)</a> 187   2.2. Text Representation of Addresses (rfc4291)</a>
188   */ 188   */
189   std::string to_string() const; 189   std::string to_string() const;
190   190  
191   /** Write a string representing the address to a buffer. 191   /** Write a string representing the address to a buffer.
192   192  
193   The resulting buffer is not null-terminated. 193   The resulting buffer is not null-terminated.
194   194  
195   @throws std::length_error `dest_size < ipv6_address::max_str_len` 195   @throws std::length_error `dest_size < ipv6_address::max_str_len`
196   196  
197   @param dest The buffer in which to write, 197   @param dest The buffer in which to write,
198   which must have at least `dest_size` space. 198   which must have at least `dest_size` space.
199   199  
200   @param dest_size The size of the output buffer. 200   @param dest_size The size of the output buffer.
201   201  
202   @return The formatted string view. 202   @return The formatted string view.
203   */ 203   */
204   std::string_view to_buffer(char* dest, std::size_t dest_size) const; 204   std::string_view to_buffer(char* dest, std::size_t dest_size) const;
205   205  
206   /** Return true if the address is unspecified. 206   /** Return true if the address is unspecified.
207   207  
208   The address 0:0:0:0:0:0:0:0 is called the 208   The address 0:0:0:0:0:0:0:0 is called the
209   unspecified address. It indicates the 209   unspecified address. It indicates the
210   absence of an address. 210   absence of an address.
211   211  
212   @return `true` if the address is unspecified. 212   @return `true` if the address is unspecified.
213   213  
214   @par Specification 214   @par Specification
215   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"> 215   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
216   2.5.2. The Unspecified Address (rfc4291)</a> 216   2.5.2. The Unspecified Address (rfc4291)</a>
217   */ 217   */
218   bool is_unspecified() const noexcept; 218   bool is_unspecified() const noexcept;
219   219  
220   /** Return true if the address is a loopback address. 220   /** Return true if the address is a loopback address.
221   221  
222   The unicast address 0:0:0:0:0:0:0:1 is called 222   The unicast address 0:0:0:0:0:0:0:1 is called
223   the loopback address. It may be used by a node 223   the loopback address. It may be used by a node
224   to send an IPv6 packet to itself. 224   to send an IPv6 packet to itself.
225   225  
226   @return `true` if the address is a loopback address. 226   @return `true` if the address is a loopback address.
227   227  
228   @par Specification 228   @par Specification
229   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> 229   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
230   2.5.3. The Loopback Address (rfc4291)</a> 230   2.5.3. The Loopback Address (rfc4291)</a>
231   */ 231   */
232   bool is_loopback() const noexcept; 232   bool is_loopback() const noexcept;
233   233  
234   /** Return true if the address is a mapped IPv4 address. 234   /** Return true if the address is a mapped IPv4 address.
235   235  
236   This address type is used to represent the 236   This address type is used to represent the
237   addresses of IPv4 nodes as IPv6 addresses. 237   addresses of IPv4 nodes as IPv6 addresses.
238   238  
239   @return `true` if the address is a mapped IPv4 address. 239   @return `true` if the address is a mapped IPv4 address.
240   240  
241   @par Specification 241   @par Specification
242   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"> 242   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
243   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> 243   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
244   */ 244   */
245   bool is_v4_mapped() const noexcept; 245   bool is_v4_mapped() const noexcept;
246   246  
247   /** Convert a v4-mapped address to the IPv4 address it maps. 247   /** Convert a v4-mapped address to the IPv4 address it maps.
248   248  
249   This is the inverse of the mapping constructor 249   This is the inverse of the mapping constructor
250   `ipv6_address(ipv4_address const&)`: it extracts the low 250   `ipv6_address(ipv4_address const&)`: it extracts the low
251   32 bits of an IPv4-Mapped IPv6 Address (`::ffff:a.b.c.d`) 251   32 bits of an IPv4-Mapped IPv6 Address (`::ffff:a.b.c.d`)
252   as an `ipv4_address`. 252   as an `ipv4_address`.
253   253  
254   @throws std::system_error `errc::address_family_not_supported` 254   @throws std::system_error `errc::address_family_not_supported`
255   if the address is not v4-mapped. 255   if the address is not v4-mapped.
256   256  
257   @return The mapped IPv4 address. 257   @return The mapped IPv4 address.
258   258  
259   @par Specification 259   @par Specification
260   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"> 260   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
261   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> 261   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
262   262  
263   @see 263   @see
264   @ref is_v4_mapped 264   @ref is_v4_mapped
265   */ 265   */
266   ipv4_address to_v4() const; 266   ipv4_address to_v4() const;
267   267  
268   /** Return true if the address is a multicast address. 268   /** Return true if the address is a multicast address.
269   269  
270   IPv6 multicast addresses have the prefix ff00::/8. 270   IPv6 multicast addresses have the prefix ff00::/8.
271   271  
272   @return `true` if the address is a multicast address. 272   @return `true` if the address is a multicast address.
273   273  
274   @par Specification 274   @par Specification
275   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7"> 275   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7">
276   2.7. Multicast Addresses (rfc4291)</a> 276   2.7. Multicast Addresses (rfc4291)</a>
277   */ 277   */
278   bool is_multicast() const noexcept; 278   bool is_multicast() const noexcept;
279   279  
280   /** Return true if two addresses are equal. 280   /** Return true if two addresses are equal.
281   281  
282   Addresses are equal if they have the same bytes and the 282   Addresses are equal if they have the same bytes and the
283   same zone: the same link-local bits on different links are 283   same zone: the same link-local bits on different links are
284   different destinations. 284   different destinations.
285   285  
286   @return `true` if the addresses are equal. 286   @return `true` if the addresses are equal.
287   */ 287   */
288   friend bool 288   friend bool
HITCBC 289   52 operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept 289   52 operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
290   { 290   {
HITCBC 291   52 return a1.addr_ == a2.addr_ && a1.scope_id_ == a2.scope_id_; 291   52 return a1.addr_ == a2.addr_ && a1.scope_id_ == a2.scope_id_;
292   } 292   }
293   293  
294   /** Order two addresses. 294   /** Order two addresses.
295   295  
296   Establishes a strict total ordering consistent with 296   Establishes a strict total ordering consistent with
297   `operator==`: addresses are ordered lexicographically by 297   `operator==`: addresses are ordered lexicographically by
298   their bytes in network order, then by zone. This makes 298   their bytes in network order, then by zone. This makes
299   `ipv6_address` usable as a key in ordered containers such 299   `ipv6_address` usable as a key in ordered containers such
300   as `std::map` and `std::set`. 300   as `std::map` and `std::set`.
301   301  
302   @return The relative order of `a1` and `a2`. 302   @return The relative order of `a1` and `a2`.
303   */ 303   */
304   friend std::strong_ordering 304   friend std::strong_ordering
HITCBC 305   17 operator<=>(ipv6_address const& a1, ipv6_address const& a2) noexcept 305   17 operator<=>(ipv6_address const& a1, ipv6_address const& a2) noexcept
306   { 306   {
HITCBC 307   17 if (auto c = a1.addr_ <=> a2.addr_; c != 0) 307   17 if (auto c = a1.addr_ <=> a2.addr_; c != 0)
HITCBC 308   6 return c; 308   6 return c;
HITCBC 309   11 return a1.scope_id_ <=> a2.scope_id_; 309   11 return a1.scope_id_ <=> a2.scope_id_;
310   } 310   }
311   311  
312   /** Return an address object that represents the unspecified address. 312   /** Return an address object that represents the unspecified address.
313   313  
314   The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket 314   The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
315   to all available interfaces. 315   to all available interfaces.
316   316  
317   @return The unspecified address (::). 317   @return The unspecified address (::).
318   */ 318   */
HITCBC 319   19 static ipv6_address any() noexcept 319   19 static ipv6_address any() noexcept
320   { 320   {
HITCBC 321   19 return ipv6_address(); 321   19 return ipv6_address();
322   } 322   }
323   323  
324   /** Return an address object that represents the loopback address. 324   /** Return an address object that represents the loopback address.
325   325  
326   The unicast address 0:0:0:0:0:0:0:1 is called 326   The unicast address 0:0:0:0:0:0:0:1 is called
327   the loopback address. It may be used by a node 327   the loopback address. It may be used by a node
328   to send an IPv6 packet to itself. 328   to send an IPv6 packet to itself.
329   329  
330   @par Specification 330   @par Specification
331   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> 331   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
332   2.5.3. The Loopback Address (rfc4291)</a> 332   2.5.3. The Loopback Address (rfc4291)</a>
333   333  
334   @return The loopback address (::1). 334   @return The loopback address (::1).
335   */ 335   */
336   static ipv6_address loopback() noexcept; 336   static ipv6_address loopback() noexcept;
337   337  
338   /** Format the address to an output stream. 338   /** Format the address to an output stream.
339   339  
340   This function writes the address to an 340   This function writes the address to an
341   output stream using standard notation. 341   output stream using standard notation.
342   342  
343   @return The output stream, for chaining. 343   @return The output stream, for chaining.
344   344  
345   @param os The output stream to write to. 345   @param os The output stream to write to.
346   346  
347   @param addr The address to write. 347   @param addr The address to write.
348   */ 348   */
349   friend BOOST_COROSIO_DECL std::ostream& 349   friend BOOST_COROSIO_DECL std::ostream&
350   operator<<(std::ostream& os, ipv6_address const& addr); 350   operator<<(std::ostream& os, ipv6_address const& addr);
351   351  
352   private: 352   private:
353   std::size_t print_impl(char* dest) const noexcept; 353   std::size_t print_impl(char* dest) const noexcept;
354   }; 354   };
355   355  
356   /** Create an IPv6 address from a string. 356   /** Create an IPv6 address from a string.
357   357  
358   This function attempts to parse the string as an IPv6 address. It 358   This function attempts to parse the string as an IPv6 address. It
359   returns an error code if the string holds no valid IPv6 address. 359   returns an error code if the string holds no valid IPv6 address.
360   360  
361   @par Exception Safety 361   @par Exception Safety
362   Throws nothing. 362   Throws nothing.
363   363  
364   @par Specification 364   @par Specification
365   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 365   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
366   >3.2.2. Host (rfc3986)</a> 366   >3.2.2. Host (rfc3986)</a>
367   367  
368   @param s The string to parse. 368   @param s The string to parse.
369   @return The error code, empty on success, and the parsed 369   @return The error code, empty on success, and the parsed
370   address — default-constructed on failure. 370   address — default-constructed on failure.
371   */ 371   */
372   [[nodiscard]] BOOST_COROSIO_DECL capy::results<ipv6_address> 372   [[nodiscard]] BOOST_COROSIO_DECL capy::results<ipv6_address>
373   make_ipv6_address(std::string_view s) noexcept; 373   make_ipv6_address(std::string_view s) noexcept;
374   374  
375   } // namespace boost::corosio 375   } // namespace boost::corosio
376   376  
377   namespace std { 377   namespace std {
378   378  
379   /// Hash support for `boost::corosio::ipv6_address`. 379   /// Hash support for `boost::corosio::ipv6_address`.
380   template<> 380   template<>
381   struct hash<boost::corosio::ipv6_address> 381   struct hash<boost::corosio::ipv6_address>
382   { 382   {
383   /// Return the hash of `addr`. 383   /// Return the hash of `addr`.
384   std::size_t 384   std::size_t
HITCBC 385   21 operator()(boost::corosio::ipv6_address const& addr) const noexcept 385   21 operator()(boost::corosio::ipv6_address const& addr) const noexcept
386   { 386   {
HITCBC 387   21 auto const bytes = addr.to_bytes(); 387   21 auto const bytes = addr.to_bytes();
HITCBC 388   21 auto const h = hash<std::string_view>()(std::string_view( 388   21 auto const h = hash<std::string_view>()(std::string_view(
HITCBC 389   21 reinterpret_cast<char const*>(bytes.data()), bytes.size())); 389   21 reinterpret_cast<char const*>(bytes.data()), bytes.size()));
390   // The zone participates in equality, so it must feed the 390   // The zone participates in equality, so it must feed the
391   // hash; combine so it cannot cancel the byte entropy 391   // hash; combine so it cannot cancel the byte entropy
HITCBC 392   21 auto const z = hash<std::uint32_t>()(addr.scope_id()); 392   21 auto const z = hash<std::uint32_t>()(addr.scope_id());
HITCBC 393   21 return h ^ (z + 0x9e3779b9u + (h << 6) + (h >> 2)); 393   21 return h ^ (z + 0x9e3779b9u + (h << 6) + (h >> 2));
394   } 394   }
395   }; 395   };
396   396  
397   } // namespace std 397   } // namespace std
398   398  
399   #endif 399   #endif