libfly  6.2.2
C++20 utility library for Linux, macOS, and Windows
ipv6_address.hpp
1 #pragma once
2 
3 #include "fly/fly.hpp"
4 #include "fly/types/string/lexer.hpp"
5 #include "fly/types/string/string.hpp"
6 
7 #include <algorithm>
8 #include <array>
9 #include <compare>
10 #include <cstdint>
11 #include <limits>
12 #include <optional>
13 #include <string>
14 
15 namespace fly::net {
16 
25 {
26 public:
27  using address_type = std::array<std::uint8_t, 16>;
28 
32  IPv6Address() = default;
33 
40  explicit constexpr IPv6Address(const address_type &address) noexcept;
41 
48  explicit constexpr IPv6Address(address_type &&address) noexcept;
49 
56  explicit constexpr IPv6Address(const address_type::value_type (&address)[16]) noexcept;
57 
58  IPv6Address(const IPv6Address &) = default;
59  IPv6Address(IPv6Address &&) = default;
60 
61  IPv6Address &operator=(const IPv6Address &) = default;
62  IPv6Address &operator=(IPv6Address &&) = default;
63 
67  static constexpr IPv6Address in_addr_any();
68 
72  static constexpr IPv6Address in_addr_loopback();
73 
87  static constexpr std::optional<IPv6Address> from_string(std::string_view address);
88 
94  constexpr void copy(address_type::value_type (&address)[16]) const;
95 
96 #if defined(FLY_MACOS)
101  constexpr bool operator==(const IPv6Address &address) const;
102  constexpr bool operator!=(const IPv6Address &address) const;
103  constexpr bool operator<(const IPv6Address &address) const;
104  constexpr bool operator<=(const IPv6Address &address) const;
105  constexpr bool operator>(const IPv6Address &address) const;
106  constexpr bool operator>=(const IPv6Address &address) const;
107 #else
111  auto operator<=>(const IPv6Address &) const = default;
112 #endif
113 
114 private:
115  static constexpr std::size_t s_address_size = std::tuple_size_v<address_type>;
116  address_type m_address {};
117 };
118 
119 //==================================================================================================
120 constexpr IPv6Address::IPv6Address(const address_type &address) noexcept : m_address {address}
121 {
122 }
123 
124 //==================================================================================================
125 constexpr IPv6Address::IPv6Address(address_type &&address) noexcept : m_address {std::move(address)}
126 {
127 }
128 
129 //==================================================================================================
130 constexpr IPv6Address::IPv6Address(const address_type::value_type (&address)[16]) noexcept
131 {
132  std::copy(std::begin(address), std::end(address), m_address.begin());
133 }
134 
135 //==================================================================================================
137 {
138  address_type address {};
139  return IPv6Address(std::move(address));
140 }
141 
142 //==================================================================================================
144 {
145  address_type address {};
146  address.back() = 0x01;
147 
148  return IPv6Address(std::move(address));
149 }
150 
151 //==================================================================================================
152 constexpr std::optional<IPv6Address> IPv6Address::from_string(std::string_view address)
153 {
154  constexpr const auto s_max16 =
155  static_cast<std::uint64_t>(std::numeric_limits<std::uint16_t>::max());
156  constexpr const auto s_colon = ':';
157 
158  fly::Lexer lexer(std::move(address));
159  address_type parts {};
160 
161  std::optional<std::size_t> index_after_short_form;
162  std::size_t index = 0;
163 
164  do
165  {
166  if (lexer.consume_if(s_colon))
167  {
168  if (lexer.consume_if(s_colon))
169  {
170  if (index_after_short_form)
171  {
172  return std::nullopt;
173  }
174 
175  index_after_short_form = index;
176  }
177  }
178  else if (const auto segment = lexer.consume_hex_number(); segment && (*segment <= s_max16))
179  {
180  parts[index++] = static_cast<address_type::value_type>((*segment >> 8) & 0xff);
181  parts[index++] = static_cast<address_type::value_type>(*segment & 0xff);
182  }
183  else
184  {
185  return std::nullopt;
186  }
187  } while (lexer.peek() && (index < s_address_size));
188 
189  if (lexer.peek() || ((index != s_address_size) && !index_after_short_form))
190  {
191  return std::nullopt;
192  }
193  else if (index_after_short_form)
194  {
195  const auto start = static_cast<std::ptrdiff_t>(s_address_size - index);
196  const auto end = static_cast<std::ptrdiff_t>(*index_after_short_form);
197 
198  std::rotate(parts.rbegin(), parts.rbegin() + start, parts.rend() - end);
199  }
200 
201  return IPv6Address(std::move(parts));
202 }
203 
204 //==================================================================================================
205 constexpr void IPv6Address::copy(address_type::value_type (&address)[16]) const
206 {
207  std::copy(m_address.begin(), m_address.end(), std::begin(address));
208 }
209 
210 #if defined(FLY_MACOS)
211 
212 //==================================================================================================
213 constexpr bool IPv6Address::operator==(const IPv6Address &address) const
214 {
215  return m_address == address.m_address;
216 }
217 
218 //==================================================================================================
219 constexpr bool IPv6Address::operator!=(const IPv6Address &address) const
220 {
221  return m_address != address.m_address;
222 }
223 
224 //==================================================================================================
225 constexpr bool IPv6Address::operator<(const IPv6Address &address) const
226 {
227  return m_address < address.m_address;
228 }
229 
230 //==================================================================================================
231 constexpr bool IPv6Address::operator<=(const IPv6Address &address) const
232 {
233  return m_address <= address.m_address;
234 }
235 
236 //==================================================================================================
237 constexpr bool IPv6Address::operator>(const IPv6Address &address) const
238 {
239  return m_address > address.m_address;
240 }
241 
242 //==================================================================================================
243 constexpr bool IPv6Address::operator>=(const IPv6Address &address) const
244 {
245  return m_address >= address.m_address;
246 }
247 
248 #endif
249 
250 } // namespace fly::net
251 
252 //==================================================================================================
253 template <>
255 {
264  template <typename FormatContext>
265  void format(const fly::net::IPv6Address &address, FormatContext &context)
266  {
267  static constexpr std::size_t s_address_size =
268  std::tuple_size_v<fly::net::IPv6Address::address_type>;
269 
270  fly::net::IPv6Address::address_type::value_type parts[s_address_size] {};
271  address.copy(parts);
272 
273  auto join_segments = [&parts](std::size_t index) -> std::uint16_t {
274  return (parts[index] << 8) | parts[index + 1];
275  };
276 
277  bool used_short_form = false;
278 
279  for (std::size_t i = 0; i < s_address_size;)
280  {
281  const std::uint16_t segment = join_segments(i);
282 
283  if ((segment == 0) && !used_short_form)
284  {
285  do
286  {
287  i += 2;
288  } while ((i < s_address_size) && (join_segments(i) == 0));
289 
290  fly::String::format_to(context.out(), "{}", (i < s_address_size) ? ":" : "::");
291  used_short_form = true;
292  }
293  else
294  {
295  fly::String::format_to(context.out(), "{:.{}}{:x}", ":", (i > 0) ? 1 : 0, segment);
296  i += 2;
297  }
298  }
299  }
300 };
Definition: lexer.hpp:31
constexpr std::optional< std::uintmax_t > consume_hex_number()
Definition: lexer.hpp:245
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: ipv6_address.hpp:25
static constexpr std::optional< IPv6Address > from_string(std::string_view address)
Definition: ipv6_address.hpp:152
static constexpr IPv6Address in_addr_loopback()
Definition: ipv6_address.hpp:143
constexpr void copy(address_type::value_type(&address)[16]) const
Definition: ipv6_address.hpp:205
auto operator<=>(const IPv6Address &) const =default
static constexpr IPv6Address in_addr_any()
Definition: ipv6_address.hpp:136
void format(const fly::net::IPv6Address &address, FormatContext &context)
Definition: ipv6_address.hpp:265
Definition: formatters.hpp:42