100.00% Lines (13/13) 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_IPV4_ADDRESS_HPP 11   #ifndef BOOST_COROSIO_IPV4_ADDRESS_HPP
12   #define BOOST_COROSIO_IPV4_ADDRESS_HPP 12   #define BOOST_COROSIO_IPV4_ADDRESS_HPP
13   13  
14   #include <boost/corosio/detail/config.hpp> 14   #include <boost/corosio/detail/config.hpp>
15   15  
16   #include <boost/capy/io_result.hpp> 16   #include <boost/capy/io_result.hpp>
17   17  
18   #include <array> 18   #include <array>
  19 + #include <compare>
19   #include <cstdint> 20   #include <cstdint>
  21 + #include <functional>
20   #include <iosfwd> 22   #include <iosfwd>
21   #include <string> 23   #include <string>
22   #include <string_view> 24   #include <string_view>
23   #include <system_error> 25   #include <system_error>
24   26  
25   namespace boost::corosio { 27   namespace boost::corosio {
26   28  
27   /** An IP version 4 style address. 29   /** An IP version 4 style address.
28   30  
29   Objects of this type are used to construct, 31   Objects of this type are used to construct,
30   parse, and manipulate IP version 4 addresses. 32   parse, and manipulate IP version 4 addresses.
31   33  
32   @par BNF 34   @par BNF
33   @code 35   @code
34   IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet 36   IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
35   37  
36   dec-octet = DIGIT ; 0-9 38   dec-octet = DIGIT ; 0-9
37   / %x31-39 DIGIT ; 10-99 39   / %x31-39 DIGIT ; 10-99
38   / "1" 2DIGIT ; 100-199 40   / "1" 2DIGIT ; 100-199
39   / "2" %x30-34 DIGIT ; 200-249 41   / "2" %x30-34 DIGIT ; 200-249
40   / "25" %x30-35 ; 250-255 42   / "25" %x30-35 ; 250-255
41   @endcode 43   @endcode
42   44  
43   @par Specification 45   @par Specification
44   @li <a href="https://en.wikipedia.org/wiki/IPv4">IPv4 (Wikipedia)</a> 46   @li <a href="https://en.wikipedia.org/wiki/IPv4">IPv4 (Wikipedia)</a>
45   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 47   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
46   >3.2.2. Host (rfc3986)</a> 48   >3.2.2. Host (rfc3986)</a>
47   49  
48   @see 50   @see
49   @ref make_ipv4_address, 51   @ref make_ipv4_address,
50   @ref ipv6_address. 52   @ref ipv6_address.
51   */ 53   */
52   class BOOST_COROSIO_DECL ipv4_address 54   class BOOST_COROSIO_DECL ipv4_address
53   { 55   {
54   std::uint32_t addr_ = 0; 56   std::uint32_t addr_ = 0;
55   57  
56   public: 58   public:
57   /** The number of characters in the longest possible IPv4 string. 59   /** The number of characters in the longest possible IPv4 string.
58   60  
59   The longest IPv4 address string is "255.255.255.255". 61   The longest IPv4 address string is "255.255.255.255".
60   */ 62   */
61   static constexpr std::size_t max_str_len = 15; 63   static constexpr std::size_t max_str_len = 15;
62   64  
63   /** The type used to represent an address as an unsigned integer. 65   /** The type used to represent an address as an unsigned integer.
64   */ 66   */
65   using uint_type = std::uint32_t; 67   using uint_type = std::uint32_t;
66   68  
67   /** The type used to represent an address as an array of bytes. 69   /** The type used to represent an address as an array of bytes.
68   */ 70   */
69   using bytes_type = std::array<unsigned char, 4>; 71   using bytes_type = std::array<unsigned char, 4>;
70   72  
71   /** Default constructor. 73   /** Default constructor.
72   74  
73   Constructs the unspecified address (0.0.0.0). 75   Constructs the unspecified address (0.0.0.0).
74   */ 76   */
HITCBC 75   147534 ipv4_address() = default; 77   145654 ipv4_address() = default;
76   78  
77   /** Copy constructor. 79   /** Copy constructor.
78   */ 80   */
79   ipv4_address(ipv4_address const&) = default; 81   ipv4_address(ipv4_address const&) = default;
80   82  
81   /** Copy assignment. 83   /** Copy assignment.
82   84  
83   @return A reference to this object. 85   @return A reference to this object.
84   */ 86   */
85   ipv4_address& operator=(ipv4_address const&) = default; 87   ipv4_address& operator=(ipv4_address const&) = default;
86   88  
87   /** Construct from an unsigned integer. 89   /** Construct from an unsigned integer.
88   90  
89   This function constructs an address from 91   This function constructs an address from
90   the unsigned integer `u`, where the most 92   the unsigned integer `u`, where the most
91   significant byte forms the first octet 93   significant byte forms the first octet
92   of the resulting address. 94   of the resulting address.
93   95  
94   @param u The integer to construct from. 96   @param u The integer to construct from.
95   */ 97   */
96   explicit ipv4_address(uint_type u) noexcept; 98   explicit ipv4_address(uint_type u) noexcept;
97   99  
98   /** Construct from an array of bytes. 100   /** Construct from an array of bytes.
99   101  
100   This function constructs an address 102   This function constructs an address
101   from the array in `bytes`, which is 103   from the array in `bytes`, which is
102   interpreted in big-endian. 104   interpreted in big-endian.
103   105  
104   @param bytes The value to construct from. 106   @param bytes The value to construct from.
105   */ 107   */
106   explicit ipv4_address(bytes_type const& bytes) noexcept; 108   explicit ipv4_address(bytes_type const& bytes) noexcept;
107   109  
108   /** Construct from a string. 110   /** Construct from a string.
109   111  
110   This function constructs an address from 112   This function constructs an address from
111   the string `s`, which must contain a valid 113   the string `s`, which must contain a valid
112   IPv4 address string or else an exception 114   IPv4 address string or else an exception
113   is thrown. 115   is thrown.
114 - @note For a non-throwing parse function,  
115 - use @ref make_ipv4_address.  
116 -  
117   116  
118   @par Exception Safety 117   @par Exception Safety
119 - Exceptions thrown on invalid input. 118 + Strong guarantee.
120   119  
121   @throws std::system_error `errc::invalid_argument` if the input 120   @throws std::system_error `errc::invalid_argument` if the input
122   failed to parse correctly. 121   failed to parse correctly.
123   122  
  123 + @note For a non-throwing parse function,
  124 + use @ref make_ipv4_address.
  125 +
124   @param s The string to parse. 126   @param s The string to parse.
125   127  
126   @par Specification 128   @par Specification
127   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 129   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
128   >3.2.2. Host (rfc3986)</a> 130   >3.2.2. Host (rfc3986)</a>
129   131  
130   @see 132   @see
131   @ref make_ipv4_address. 133   @ref make_ipv4_address.
132   */ 134   */
133   explicit ipv4_address(std::string_view s); 135   explicit ipv4_address(std::string_view s);
134   136  
135   /** Return the address as bytes, in network byte order. 137   /** Return the address as bytes, in network byte order.
136   138  
137   @return The address as an array of bytes. 139   @return The address as an array of bytes.
138   */ 140   */
139   bytes_type to_bytes() const noexcept; 141   bytes_type to_bytes() const noexcept;
140   142  
141   /** Return the address as an unsigned integer. 143   /** Return the address as an unsigned integer.
142   144  
143   @return The address as an unsigned integer. 145   @return The address as an unsigned integer.
144   */ 146   */
145   uint_type to_uint() const noexcept; 147   uint_type to_uint() const noexcept;
146   148  
147   /** Return the address as a string in dotted decimal format. 149   /** Return the address as a string in dotted decimal format.
148   150  
149   @par Example 151   @par Example
150   @par !example to_string 152   @par !example to_string
151   153  
152   @return The address as a string. 154   @return The address as a string.
153   */ 155   */
154   std::string to_string() const; 156   std::string to_string() const;
155   157  
156   /** Write a dotted decimal string representing the address to a buffer. 158   /** Write a dotted decimal string representing the address to a buffer.
157   159  
158   The resulting buffer is not null-terminated. 160   The resulting buffer is not null-terminated.
159   161  
160 - @throw std::length_error `dest_size < ipv4_address::max_str_len` 162 + @throws std::length_error `dest_size < ipv4_address::max_str_len`
161 -  
162 - @return The formatted string view.  
163   163  
164   @param dest The buffer in which to write, 164   @param dest The buffer in which to write,
165   which must have at least `dest_size` space. 165   which must have at least `dest_size` space.
166   166  
167   @param dest_size The size of the output buffer. 167   @param dest_size The size of the output buffer.
  168 +
  169 + @return The formatted string view.
168   */ 170   */
169   std::string_view to_buffer(char* dest, std::size_t dest_size) const; 171   std::string_view to_buffer(char* dest, std::size_t dest_size) const;
170   172  
171   /** Return true if the address is a loopback address. 173   /** Return true if the address is a loopback address.
172   174  
173   @return `true` if the address is a loopback address. 175   @return `true` if the address is a loopback address.
174   */ 176   */
175   bool is_loopback() const noexcept; 177   bool is_loopback() const noexcept;
176   178  
177   /** Return true if the address is unspecified. 179   /** Return true if the address is unspecified.
178   180  
179   @return `true` if the address is unspecified. 181   @return `true` if the address is unspecified.
180   */ 182   */
181   bool is_unspecified() const noexcept; 183   bool is_unspecified() const noexcept;
182   184  
183   /** Return true if the address is a multicast address. 185   /** Return true if the address is a multicast address.
184   186  
185   @return `true` if the address is a multicast address. 187   @return `true` if the address is a multicast address.
186   */ 188   */
187   bool is_multicast() const noexcept; 189   bool is_multicast() const noexcept;
188   190  
189   /** Return true if two addresses are equal. 191   /** Return true if two addresses are equal.
190   192  
191   @return `true` if the addresses are equal, otherwise `false`. 193   @return `true` if the addresses are equal, otherwise `false`.
192   */ 194   */
193   friend bool 195   friend bool
HITCBC 194   129 operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept 196   157 operator==(ipv4_address const& a1, ipv4_address const& a2) noexcept
195   { 197   {
HITCBC 196   129 return a1.addr_ == a2.addr_; 198   157 return a1.addr_ == a2.addr_;
197   } 199   }
198   200  
199 - /** Return true if two addresses are not equal. 201 + /** Order two addresses.
200   202  
201 - @return `true` if the addresses are not equal, otherwise `false`. 203 + Establishes a strict total ordering consistent with
  204 + `operator==`: addresses are ordered by their integer
  205 + value, most significant octet first. This makes
  206 + `ipv4_address` usable as a key in ordered containers
  207 + such as `std::map` and `std::set`.
  208 +
  209 + @return The relative order of `a1` and `a2`.
202   */ 210   */
203 - friend bool 211 + friend std::strong_ordering
HITCBC 204 - 2 operator!=(ipv4_address const& a1, ipv4_address const& a2) noexcept 212 + 23 operator<=>(ipv4_address const& a1, ipv4_address const& a2) noexcept
205   { 213   {
HITCBC 206 - 2 return a1.addr_ != a2.addr_; 214 + 23 return a1.addr_ <=> a2.addr_;
207   } 215   }
208   216  
209   /** Return an address object that represents any address. 217   /** Return an address object that represents any address.
210   218  
211   @return The any address (0.0.0.0). 219   @return The any address (0.0.0.0).
212   */ 220   */
HITCBC 213   147438 static ipv4_address any() noexcept 221   28 static ipv4_address any() noexcept
214   { 222   {
HITCBC 215   147438 return ipv4_address(); 223   28 return ipv4_address();
216   } 224   }
217   225  
218   /** Return an address object that represents the loopback address. 226   /** Return an address object that represents the loopback address.
219   227  
220   @return The loopback address (127.0.0.1). 228   @return The loopback address (127.0.0.1).
221   */ 229   */
HITCBC 222   5198 static ipv4_address loopback() noexcept 230   5307 static ipv4_address loopback() noexcept
223   { 231   {
HITCBC 224   5198 return ipv4_address(0x7F000001); 232   5307 return ipv4_address(0x7F000001);
225   } 233   }
226   234  
227   /** Return an address object that represents the broadcast address. 235   /** Return an address object that represents the broadcast address.
228   236  
229   @return The broadcast address (255.255.255.255). 237   @return The broadcast address (255.255.255.255).
230   */ 238   */
HITCBC 231   3 static ipv4_address broadcast() noexcept 239   6 static ipv4_address broadcast() noexcept
232   { 240   {
HITCBC 233   3 return ipv4_address(0xFFFFFFFF); 241   6 return ipv4_address(0xFFFFFFFF);
234   } 242   }
235   243  
236   /** Format the address to an output stream. 244   /** Format the address to an output stream.
237   245  
238   IPv4 addresses written to output streams 246   IPv4 addresses written to output streams
239   are written in their dotted decimal format. 247   are written in their dotted decimal format.
240   248  
241   @param os The output stream. 249   @param os The output stream.
242   @param addr The address to format. 250   @param addr The address to format.
243   @return The output stream. 251   @return The output stream.
244   */ 252   */
245   friend BOOST_COROSIO_DECL std::ostream& 253   friend BOOST_COROSIO_DECL std::ostream&
246   operator<<(std::ostream& os, ipv4_address const& addr); 254   operator<<(std::ostream& os, ipv4_address const& addr);
247   255  
248   private: 256   private:
249   friend class ipv6_address; 257   friend class ipv6_address;
250   258  
251   std::size_t print_impl(char* dest) const noexcept; 259   std::size_t print_impl(char* dest) const noexcept;
252   }; 260   };
253   261  
254   /** Create an IPv4 address from an IP address string in dotted decimal form. 262   /** Create an IPv4 address from an IP address string in dotted decimal form.
255   263  
256   @param s The string to parse. 264   @param s The string to parse.
257   @return The error code, empty on success, and the parsed 265   @return The error code, empty on success, and the parsed
258   address — default-constructed on failure. 266   address — default-constructed on failure.
259   */ 267   */
260   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<ipv4_address> 268   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<ipv4_address>
261   make_ipv4_address(std::string_view s) noexcept; 269   make_ipv4_address(std::string_view s) noexcept;
262   270  
263   } // namespace boost::corosio 271   } // namespace boost::corosio
  272 +
  273 + namespace std {
  274 +
  275 + /// Hash support for `boost::corosio::ipv4_address`.
  276 + template<>
  277 + struct hash<boost::corosio::ipv4_address>
  278 + {
  279 + /// Return the hash of `addr`.
  280 + std::size_t
HITGNC   281 + 20 operator()(boost::corosio::ipv4_address const& addr) const noexcept
  282 + {
HITGNC   283 + 20 return hash<std::uint32_t>()(addr.to_uint());
  284 + }
  285 + };
  286 +
  287 + } // namespace std
264   288  
265   #endif 289   #endif