libfly  6.2.2
C++20 utility library for Linux, macOS, and Windows
ipv4_address.hpp
1 #pragma once
2 
3 #include "fly/types/numeric/endian.hpp"
4 #include "fly/types/string/lexer.hpp"
5 #include "fly/types/string/string.hpp"
6 
7 #include <array>
8 #include <compare>
9 #include <cstdint>
10 #include <limits>
11 #include <optional>
12 #include <string>
13 
14 namespace fly::net {
15 
24 {
25 public:
26  using address_type = std::array<std::uint8_t, 4>;
27  using int_type = std::uint32_t;
28 
32  IPv4Address() = default;
33 
40  explicit constexpr IPv4Address(const address_type &address) noexcept;
41 
47  explicit constexpr IPv4Address(int_type address) noexcept;
48 
49  IPv4Address(const IPv4Address &) = default;
50  IPv4Address(IPv4Address &&) = default;
51 
52  IPv4Address &operator=(const IPv4Address &) = default;
53  IPv4Address &operator=(IPv4Address &&) = default;
54 
58  static constexpr IPv4Address in_addr_any();
59 
63  static constexpr IPv4Address in_addr_broadcast();
64 
68  static constexpr IPv4Address in_addr_loopback();
69 
82  static constexpr std::optional<IPv4Address> from_string(std::string_view address);
83 
87  constexpr int_type network_order() const;
88 
92  constexpr int_type host_order() const;
93 
98  auto operator<=>(const IPv4Address &) const = default;
99 
100 private:
101  int_type m_address {0};
102 };
103 
104 //==================================================================================================
105 constexpr IPv4Address::IPv4Address(const address_type &address) noexcept
106 {
107  m_address |= static_cast<int_type>(address[0]);
108  m_address |= static_cast<int_type>(address[1] << 8);
109  m_address |= static_cast<int_type>(address[2] << 16);
110  m_address |= static_cast<int_type>(address[3] << 24);
111 }
112 
113 //==================================================================================================
114 constexpr IPv4Address::IPv4Address(int_type address) noexcept : m_address(address)
115 {
116 }
117 
118 //==================================================================================================
120 {
121  return IPv4Address(0x00'00'00'00);
122 }
123 
124 //==================================================================================================
126 {
127  return IPv4Address(0xff'ff'ff'ff);
128 }
129 
130 //==================================================================================================
132 {
133  return IPv4Address(0x01'00'00'7f);
134 }
135 
136 //==================================================================================================
137 constexpr std::optional<IPv4Address> IPv4Address::from_string(std::string_view address)
138 {
139  constexpr const auto s_max32 = static_cast<std::uint64_t>(std::numeric_limits<int_type>::max());
140  constexpr const auto s_decimal = '.';
141 
142  fly::Lexer lexer(std::move(address));
143 
144  std::array<int_type, 4> parts {};
145  std::size_t index = 0;
146 
147  do
148  {
149  if (const auto segment = lexer.consume_number(); segment && (*segment <= s_max32))
150  {
151  parts[index++] = static_cast<int_type>(*segment);
152  }
153  else
154  {
155  return std::nullopt;
156  }
157  } while ((index < parts.size()) && lexer.consume_if(s_decimal));
158 
159  std::optional<int_type> host_address;
160 
161  if (index == 1)
162  {
163  host_address = parts[0];
164  }
165  else if (index == 2)
166  {
167  if ((parts[0] <= 0xff) && (parts[1] <= 0xff'ff'ff))
168  {
169  host_address = (parts[0] << 24) | parts[1];
170  }
171  }
172  else if (index == 3)
173  {
174  if ((parts[0] <= 0xff) && (parts[1] <= 0xff) && (parts[2] <= 0xff'ff))
175  {
176  host_address = (parts[0] << 24) | (parts[1] << 16) | parts[2];
177  }
178  }
179  else if (index == 4)
180  {
181  if ((parts[0] <= 0xff) && (parts[1] <= 0xff) && (parts[2] <= 0xff) && (parts[3] <= 0xff))
182  {
183  host_address = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
184  }
185  }
186 
187  if (!host_address || lexer.peek())
188  {
189  return std::nullopt;
190  }
191 
192  return IPv4Address(fly::endian_swap_if_non_native<std::endian::big>(*host_address));
193 }
194 
195 //==================================================================================================
196 constexpr auto IPv4Address::network_order() const -> int_type
197 {
198  return m_address;
199 }
200 
201 //==================================================================================================
202 constexpr auto IPv4Address::host_order() const -> int_type
203 {
204  return fly::endian_swap_if_non_native<std::endian::big>(m_address);
205 }
206 
207 } // namespace fly::net
208 
209 //==================================================================================================
210 template <>
212 {
221  template <typename FormatContext>
222  void format(const fly::net::IPv4Address &address, FormatContext &context)
223  {
224  const auto network_order = address.network_order();
225 
227  context.out(),
228  "{}.{}.{}.{}",
229  network_order & 0xff,
230  (network_order >> 8) & 0xff,
231  (network_order >> 16) & 0xff,
232  (network_order >> 24) & 0xff);
233  }
234 };
Definition: lexer.hpp:31
constexpr std::optional< std::uintmax_t > consume_number()
Definition: lexer.hpp:227
constexpr bool consume_if(CharType ch)
Definition: lexer.hpp:214
constexpr std::optional< CharType > peek(std::size_t offset=0)
Definition: lexer.hpp:190
static void format_to(OutputIterator output, FormatString< ParameterTypes... > &&fmt, ParameterTypes &&...parameters)
Definition: string.hpp:939
Definition: ipv4_address.hpp:24
constexpr int_type host_order() const
Definition: ipv4_address.hpp:202
static constexpr IPv4Address in_addr_broadcast()
Definition: ipv4_address.hpp:125
static constexpr IPv4Address in_addr_any()
Definition: ipv4_address.hpp:119
static constexpr std::optional< IPv4Address > from_string(std::string_view address)
Definition: ipv4_address.hpp:137
constexpr int_type network_order() const
Definition: ipv4_address.hpp:196
auto operator<=>(const IPv4Address &) const =default
static constexpr IPv4Address in_addr_loopback()
Definition: ipv4_address.hpp:131
void format(const fly::net::IPv4Address &address, FormatContext &context)
Definition: ipv4_address.hpp:222
Definition: formatters.hpp:42