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