ipaddress 1.1.0
Loading...
Searching...
No Matches
ipv6-address.hpp
Go to the documentation of this file.
1/**
2 * @file ipv6-address.hpp
3 * @brief Provides a set of functions and classes for handling IPv6 addresses
4 * @author Vladimir Shaleev
5 * @copyright MIT License
6 *
7 * Includes functionalities to convert IPv6 addresses to and from various formats,
8 * perform comparisons, and query specific properties of the addresses.
9 * It serves as a foundational component for network applications that require manipulation
10 * and analysis of IPv6 address data.
11 */
12
13#ifndef IPADDRESS_IPV6_ADDRESS_HPP
14#define IPADDRESS_IPV6_ADDRESS_HPP
15
16#include "ipv4-address.hpp"
17#include "base-v6.hpp"
18
19namespace IPADDRESS_NAMESPACE {
20
21namespace internal {
22
23template <typename T>
24struct ipv6_set_scope {
25 template <typename Str>
26 static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void change(fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH>& result, const Str& scope) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
27 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
29 uint32_t index = 0;
30 change(result, scope, code, index);
31 #ifndef IPADDRESS_NO_EXCEPTIONS
32 if (code != error_code::no_error) {
33 raise_error(code, index, scope.data(), scope.size());
34 }
35 #endif // !IPADDRESS_NO_EXCEPTIONS
36 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
37 }
38
39 template <typename Str>
40 static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void change(fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH>& result, const Str& scope, error_code& code) IPADDRESS_NOEXCEPT {
41 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
42 uint32_t index = 0;
43 change(result, scope, code, index);
44 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
45 }
46
47 template <typename Str>
48 static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void change(fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH>& result, const Str& scope, error_code& code, uint32_t& index) IPADDRESS_NOEXCEPT {
49 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
50 if (scope.size() > IPADDRESS_IPV6_SCOPE_MAX_LENGTH) {
52 return;
53 }
54 char str[IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1] = {};
55 auto it = scope.data();
56 auto end = it + scope.size();
57 uint32_t error_symbol = 0;
59 index = 0;
60 for (int i = 0; it < end; ++i) {
61 auto c = internal::next_char_or_error(it, end, code, error_symbol);
62 if (code != error_code::no_error) {
63 index = error_symbol;
64 return;
65 }
66 if (internal::is_invalid_scope_id_symbol(c)) {
68 return;
69 }
70 str[i] = c;
71 }
72 const auto fixed_scope = make_fixed_string(str, code);
73 if (code == error_code::no_error) {
74 result = fixed_scope;
75 }
76 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
77 }
78};
79
80} // namespace IPADDRESS_NAMESPACE::internal
81
82/**
83 * Represents the scope identifier for an IPv6 address.
84 *
85 * The scope identifier is used to distinguish between different zones for the same address,
86 * such as link-local or site-local scopes. This class provides methods to set, retrieve,
87 * and compare scope identifiers in both string and numeric formats.
88 */
89IPADDRESS_EXPORT class scope final {
90public:
91 /**
92 * Constructs a scope object with a given scope identifier.
93 *
94 * @param[in] scope_id A fixed_string representing the scope identifier.
95 */
96 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE scope(const fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH>& scope_id) IPADDRESS_NOEXCEPT
97 :
99 parse_value();
100 }
101
102 /**
103 * Retrieves the scope identifier as a string.
104 *
105 * @return A `std::string` representing the scope identifier.
106 */
108 return std::string(_scope_id.begin(), _scope_id.end());
109 }
110
111 /**
112 * Retrieves the scope identifier as a numeric value.
113 *
114 * @return A uint32_t representing the numeric value of the scope identifier.
115 */
117 return _scope_id_value;
118 }
119
120 /**
121 * Checks if the scope identifier has a string representation.
122 *
123 * @return `true` if a string representation exists, `false` otherwise.
124 */
126 return !_scope_id.empty();
127 }
128
129 /**
130 * Checks if the scope identifier has a numeric representation.
131 *
132 * @return `true` if a numeric representation exists, `false` otherwise.
133 */
135 return _has_value;
136 }
137
138 /**
139 * Converts the scope object to a boolean value based on the presence of a scope representation.
140 *
141 * @return `true` if a scope exists, `false` otherwise.
142 */
143 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator bool() const IPADDRESS_NOEXCEPT {
144 return has_string();
145 }
146
147 /**
148 * Converts the scope object to a string representation.
149 *
150 * @return A std::string representing the scope identifier.
151 */
153 return get_string();
154 }
155
156 /**
157 * Converts the scope object to a numeric representation.
158 *
159 * @return A uint32_t representing the numeric value of the scope identifier.
160 */
162 return get_uint32();
163 }
164
165 /**
166 * Compares two scope objects for equality.
167 *
168 * @param[in] rhs The right-hand side scope object for comparison.
169 * @return `true` if both scope objects are equal, `false` otherwise.
170 */
171 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(const scope& rhs) const IPADDRESS_NOEXCEPT {
172 return _scope_id == rhs._scope_id;
173 }
174
175 /**
176 * Compares two scope objects for inequality.
177 *
178 * @param[in] rhs The right-hand side scope object for comparison.
179 * @return `true` if both scope objects are not equal, `false` otherwise.
180 */
181 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(const scope& rhs) const IPADDRESS_NOEXCEPT {
182 return !(*this == rhs);
183 }
184
185#ifdef IPADDRESS_HAS_SPACESHIP_OPERATOR
186
187 /**
188 * Compares two scope objects using the three-way comparison operator (spaceship operator).
189 *
190 * @param[in] rhs The right-hand side scope object for comparison.
191 * @return A value of type `std::strong_ordering` that represents the result of the comparison.
192 */
193 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::strong_ordering operator<=>(const scope& rhs) const IPADDRESS_NOEXCEPT {
194 return _scope_id <=> rhs._scope_id;
195 }
196
197#else // !IPADDRESS_HAS_SPACESHIP_OPERATOR
198
199 /**
200 * Checks if one scope object is less than another.
201 *
202 * @param[in] rhs The right-hand side scope object for comparison.
203 * @return `true` if the left-hand side scope object is less than the right-hand side, `false` otherwise.
204 */
205 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<(const scope& rhs) const IPADDRESS_NOEXCEPT {
206 return _scope_id < rhs._scope_id;
207 }
208
209 /**
210 * Checks if one scope object is greater than another.
211 *
212 * @param[in] rhs The right-hand side scope object for comparison.
213 * @return `true` if the left-hand side scope object is greater than the right-hand side, `false` otherwise.
214 */
215 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>(const scope& rhs) const IPADDRESS_NOEXCEPT {
216 return rhs < *this;
217 }
218
219 /**
220 * Checks if one scope object is less than or equal to another.
221 *
222 * @param[in] rhs The right-hand side scope object for comparison.
223 * @return `true` if the left-hand side scope object is less than or equal to the right-hand side, `false` otherwise.
224 */
225 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(const scope& rhs) const IPADDRESS_NOEXCEPT {
226 return !(rhs < *this);
227 }
228
229 /**
230 * Checks if one scope object is greater than or equal to another.
231 *
232 * @param[in] rhs The right-hand side scope object for comparison.
233 * @return `true` if the left-hand side scope object is greater than or equal to the right-hand side, `false` otherwise.
234 */
235 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(const scope& rhs) const IPADDRESS_NOEXCEPT {
236 return !(*this < rhs);
237 }
238
239#endif // !IPADDRESS_HAS_SPACESHIP_OPERATOR
240
241private:
242 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void parse_value() IPADDRESS_NOEXCEPT {
243 if (!_scope_id.empty()) {
244 _has_value = true;
245 uint32_t value = 0;
246 const auto scope_id_size = _scope_id.size();
247 for (size_t i = 0; i < scope_id_size; ++i) {
248 const auto c = _scope_id[i];
249 if (c >= '0' && c <= '9') {
250 value = value * 10 + (c - '0');
251 } else {
252 _has_value = false;
253 break;
254 }
255 }
256 _scope_id_value = _has_value ? value : 0;
257 }
258 }
259
260 fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH> _scope_id;
261 uint32_t _scope_id_value = 0;
262 bool _has_value = false;
263}; // scope
264
265/**
266 * Represents the base class for IPv6 address manipulation.
267 *
268 * This class provides the basic functionalities required for handling IPv6 addresses,
269 * including conversion to and from numeric representations, access to the underlying bytes,
270 * and utility functions that are common across different representations of IPv6 addresses.
271 */
273public:
274 using base_type = typename base_v6<ipv6_address_base>::base_type; /**< The base type for the IPv6 address. */
275 using uint_type = typename base_v6<ipv6_address_base>::uint_type; /**< The unsigned integer type for the IPv6 address. */
276
277 /**
278 * Retrieves the scope identifier of the IPv6 address.
279 *
280 * The scope identifier is used to determine the context in which the address is valid.
281 * It is particularly relevant for link-local and site-local addresses.
282 *
283 * @return A `scope` object representing the scope identifier of the IPv6 address.
284 * @remark If the scope is disabled in the settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`), then an empty scope will be returned.
285 */
287 return scope(
288 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
289 _data.scope_id
290 #else // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
291 make_fixed_string("")
292 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
293 );
294 }
295
296 /**
297 * Sets the scope identifier of the IPv6 address.
298 *
299 * This function sets the scope identifier using a character array. The length of the array
300 * should not exceed `IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1`.
301 *
302 * @tparam T The character type of the scope identifier.
303 * @tparam N The size of the scope identifier array.
304 * @param[in] scope_id The character array representing the scope identifier.
305 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
306 */
307 template <typename T, size_t N>
308 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void set_scope_id(const T(&scope_id)[N]) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
309 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
310 static_assert(N <= IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1, "scope id is too long");
311 #ifdef IPADDRESS_NO_EXCEPTIONS
312 auto code = error_code::no_error;
313 const auto result = make_fixed_string(scope_id, code);
314 if (code == error_code::no_error) {
315 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, result);
316 }
317 #else // !IPADDRESS_NO_EXCEPTIONS
318 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, make_fixed_string(scope_id));
319 #endif // !IPADDRESS_NO_EXCEPTIONS
320 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
321 }
322
323 /**
324 * Sets the scope identifier of the IPv6 address and reports any errors encountered.
325 *
326 * This function sets the scope identifier using a character array. The length of the array
327 * should not exceed `IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1`.
328 *
329 * @tparam T The character type of the scope identifier.
330 * @tparam N The size of the scope identifier array.
331 * @param[in] scope_id The character array representing the scope identifier.
332 * @param[out] code An error_code object that will be set to the error that occurred, if any.
333 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
334 */
335 template <typename T, size_t N>
336 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void set_scope_id(const T(&scope_id)[N], error_code& code) IPADDRESS_NOEXCEPT {
337 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
338 static_assert(N <= IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1, "scope id is too long");
339 const auto fixed_scope = make_fixed_string(scope_id, code);
340 if (code == error_code::no_error) {
341 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, fixed_scope, code);
342 }
343 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
344 }
345
346#if IPADDRESS_CPP_VERSION >= 17
347
348 /**
349 * Sets the scope identifier of the IPv6 address using a string view.
350 *
351 * This function sets the scope identifier using a string view, which allows for a more efficient
352 * way to handle strings without copying them.
353 *
354 * @param[in] scope_id The string view representing the scope identifier.
355 * @throw parse_error Exception caused by invalid input string.
356 * @note This method is available for C++17 and later versions.
357 * @parblock
358 * @remark For C++ versions prior to C++17, member functions with `std::string` and C-strings will be used instead.
359 * @endparblock
360 * @parblock
361 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
362 * @endparblock
363 */
365 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
367 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
368 }
369
370 /**
371 * Sets the scope identifier of the IPv6 address using a wide string view.
372 *
373 * This function sets the scope identifier using a wide string view, which allows for a more efficient
374 * way to handle strings without copying them.
375 *
376 * @param[in] scope_id The wide string view representing the scope identifier.
377 * @throw parse_error Exception caused by invalid input string.
378 * @note This method is available for C++17 and later versions.
379 * @parblock
380 * @remark For C++ versions prior to C++17, member functions with `std::wstring` and C-strings will be used instead.
381 * @endparblock
382 * @parblock
383 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
384 * @endparblock
385 */
387 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
389 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
390 }
391
392#if __cpp_char8_t >= 201811L
393
394 /**
395 * Sets the scope identifier of the IPv6 address using UTF-8 string view.
396 *
397 * This function sets the scope identifier using UTF-8 string view, which allows for a more efficient
398 * way to handle strings without copying them.
399 *
400 * @param[in] scope_id The UTF-8 string view representing the scope identifier.
401 * @throw parse_error Exception caused by invalid input string.
402 * @note This method is available for C++20 and later versions where `char8_t` is supported.
403 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
404 */
406 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
408 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
409 }
410
411#endif // __cpp_char8_t
412
413 /**
414 * Sets the scope identifier of the IPv6 address using UTF-16 string view.
415 *
416 * This function sets the scope identifier using UTF-16 string view, which allows for a more efficient
417 * way to handle strings without copying them.
418 *
419 * @param[in] scope_id The UTF-16 string view representing the scope identifier.
420 * @throw parse_error Exception caused by invalid input string.
421 * @note This method is available for C++17 and later versions.
422 * @parblock
423 * @remark For C++ versions prior to C++17, member functions with `std::u16string` and C-strings will be used instead.
424 * @endparblock
425 * @parblock
426 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
427 * @endparblock
428 */
430 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
432 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
433 }
434
435 /**
436 * Sets the scope identifier of the IPv6 address using UTF-32 string view.
437 *
438 * This function sets the scope identifier using UTF-32 string view, which allows for a more efficient
439 * way to handle strings without copying them.
440 *
441 * @param[in] scope_id The UTF-32 string view representing the scope identifier.
442 * @throw parse_error Exception caused by invalid input string.
443 * @note This method is available for C++17 and later versions.
444 * @parblock
445 * @remark For C++ versions prior to C++17, member functions with `std::u32string` and C-strings will be used instead.
446 * @endparblock
447 * @parblock
448 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
449 * @endparblock
450 */
452 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
454 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
455 }
456
457 /**
458 * Sets the scope identifier of the IPv6 address using a string view and reports any errors encountered.
459 *
460 * This function sets the scope identifier using a string view and provides an error code parameter to report any issues that occur during the operation.
461 *
462 * @param[in] scope_id The string view representing the scope identifier.
463 * @param[out] code An error_code object that will be set to the error that occurred, if any.
464 * @note This method is available for C++17 and later versions.
465 * @parblock
466 * @remark For C++ versions prior to C++17, member functions with `std::string` and C-strings will be used instead.
467 * @endparblock
468 * @parblock
469 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
470 * @endparblock
471 */
473 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
475 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
476 }
477
478 /**
479 * Sets the scope identifier of the IPv6 address using a wide string view and reports any errors encountered.
480 *
481 * This function sets the scope identifier using a wide string view and provides an error code parameter to report any issues that occur during the operation.
482 *
483 * @param[in] scope_id The wide string view representing the scope identifier.
484 * @param[out] code An error_code object that will be set to the error that occurred, if any.
485 * @note This method is available for C++17 and later versions.
486 * @parblock
487 * @remark For C++ versions prior to C++17, member functions with `std::wstring` and C-strings will be used instead.
488 * @endparblock
489 * @parblock
490 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
491 * @endparblock
492 */
494 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
496 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
497 }
498
499#if __cpp_char8_t >= 201811L
500
501 /**
502 * Sets the scope identifier of the IPv6 address using a UTF-8 string view and reports any errors encountered.
503 *
504 * This function sets the scope identifier using a UTF-8 string view and provides an error code parameter to report any issues that occur during the operation.
505 *
506 * @param[in] scope_id The UTF-8 string view representing the scope identifier.
507 * @param[out] code An error_code object that will be set to the error that occurred, if any.
508 * @note This method is available for C++20 and later versions.
509 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
510 */
512 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
514 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
515 }
516
517#endif // __cpp_char8_t
518
519 /**
520 * Sets the scope identifier of the IPv6 address using a UTF-16 string view and reports any errors encountered.
521 *
522 * This function sets the scope identifier using a UTF-16 string view and provides an error code parameter to report any issues that occur during the operation.
523 *
524 * @param[in] scope_id The UTF-16 string view representing the scope identifier.
525 * @param[out] code An error_code object that will be set to the error that occurred, if any.
526 * @note This method is available for C++17 and later versions.
527 * @parblock
528 * @remark For C++ versions prior to C++17, member functions with `std::u16string` and C-strings will be used instead.
529 * @endparblock
530 * @parblock
531 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
532 * @endparblock
533 */
535 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
537 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
538 }
539
540 /**
541 * Sets the scope identifier of the IPv6 address using a UTF-32 string view and reports any errors encountered.
542 *
543 * This function sets the scope identifier using a UTF-32 string view and provides an error code parameter to report any issues that occur during the operation.
544 *
545 * @param[in] scope_id The UTF-32 string view representing the scope identifier.
546 * @param[out] code An error_code object that will be set to the error that occurred, if any.
547 * @note This method is available for C++17 and later versions.
548 * @parblock
549 * @remark For C++ versions prior to C++17, member functions with `std::u32string` and C-strings will be used instead.
550 * @endparblock
551 * @parblock
552 * @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
553 * @endparblock
554 */
556 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
558 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
559 }
560
561#else // IPADDRESS_CPP_VERSION < 17
562
563 /**
564 * Sets the scope identifier of the IPv6 address using a `std::string`.
565 *
566 * @param[in] scope_id The string representing the scope identifier.
567 * @throw parse_error Exception caused by invalid input string.
568 */
569 IPADDRESS_FORCE_INLINE void set_scope_id(const std::string& scope_id) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
570 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
571 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id);
572 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
573 }
574
575 /**
576 * Sets the scope identifier of the IPv6 address using a `std::wstring`.
577 *
578 * @param[in] scope_id The wide string representing the scope identifier.
579 * @throw parse_error Exception caused by invalid input wide string.
580 */
581 IPADDRESS_FORCE_INLINE void set_scope_id(const std::wstring& scope_id) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
582 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
583 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id);
584 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
585 }
586
587 /**
588 * Sets the scope identifier of the IPv6 address using a `std::u16string`.
589 *
590 * @param[in] scope_id The UTF-16 string representing the scope identifier.
591 * @throw parse_error Exception caused by invalid input UTF-16 string.
592 */
593 IPADDRESS_FORCE_INLINE void set_scope_id(const std::u16string& scope_id) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
594 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
595 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id);
596 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
597 }
598
599 /**
600 * Sets the scope identifier of the IPv6 address using a `std::u32string`.
601 *
602 * @param[in] scope_id The UTF-32 string representing the scope identifier.
603 * @throw parse_error Exception caused by invalid input UTF-32 string.
604 */
605 IPADDRESS_FORCE_INLINE void set_scope_id(const std::u32string& scope_id) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
606 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
607 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id);
608 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
609 }
610
611 /**
612 * Sets the scope identifier of the IPv6 address using a `std::string` and reports any errors.
613 *
614 * @param[in] scope_id The string representing the scope identifier.
615 * @param[out] code An error_code object that will store the result of the operation.
616 */
617 IPADDRESS_FORCE_INLINE void set_scope_id(const std::string& scope_id, error_code& code) IPADDRESS_NOEXCEPT {
618 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
619 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id, code);
620 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
621 }
622
623 /**
624 * Sets the scope identifier of the IPv6 address using a `std::wstring` and reports any errors.
625 *
626 * @param[in] scope_id The wide string representing the scope identifier.
627 * @param[out] code An error_code object that will store the result of the operation.
628 */
629 IPADDRESS_FORCE_INLINE void set_scope_id(const std::wstring& scope_id, error_code& code) IPADDRESS_NOEXCEPT {
630 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
631 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id, code);
632 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
633 }
634
635 /**
636 * Sets the scope identifier of the IPv6 address using a `std::u16string` and reports any errors.
637 *
638 * @param[in] scope_id The UTF-16 string representing the scope identifier.
639 * @param[out] code An error_code object that will store the result of the operation.
640 */
641 IPADDRESS_FORCE_INLINE void set_scope_id(const std::u16string& scope_id, error_code& code) IPADDRESS_NOEXCEPT {
642 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
643 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id, code);
644 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
645 }
646
647 /**
648 * Sets the scope identifier of the IPv6 address using a `std::u32string` and reports any errors.
649 *
650 * @param[in] scope_id The UTF-32 string representing the scope identifier.
651 * @param[out] code An error_code object that will store the result of the operation.
652 */
653 IPADDRESS_FORCE_INLINE void set_scope_id(const std::u32string& scope_id, error_code& code) IPADDRESS_NOEXCEPT {
654 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
655 internal::ipv6_set_scope<ipv6_address_base>::change(_data.scope_id, scope_id, code);
656 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
657 }
658
659#endif // IPADDRESS_CPP_VERSION < 17
660
661 /**
662 * Creates an IPv6 address from an unsigned integer using a template parameter.
663 *
664 * @param[in] ip The unsigned integer representing the IPv6 address.
665 * @return An instance of ip address representing the IPv6 address.
666 */
669 auto& bytes = result._data.bytes;
670 int shift = 0;
671 int inc = 8;
672 if (is_little_endian()) {
673 shift = 56;
674 inc = -8;
675 }
676 for (int i = 0, s = shift; i < 8; ++i, s += inc) {
677 bytes[i] = uint8_t(ip.upper() >> s);
678 bytes[i + 8] = uint8_t(ip.lower() >> s);
679 }
680 return result;
681 }
682
683 /**
684 * Converts the IPv6 address to an unsigned integer.
685 *
686 * @return The unsigned integer representation of the IPv6 address.
687 * @remark Bytes in integer are presented in **host byte order**.
688 */
690 const auto& bytes = _data.bytes;
691 uint64_t upper = 0;
692 uint64_t lower = 0;
693 int shift = 0;
694 int inc = 8;
695 if (is_little_endian()) {
696 shift = 56;
697 inc = -8;
698 }
699 for (int i = 0, s = shift; i < 8; ++i, s += inc) {
700 upper |= uint64_t(bytes[i]) << s;
701 lower |= uint64_t(bytes[i + 8]) << s;
702 }
703 return uint_type(upper, lower);
704 }
705
706 /**
707 * Provides access to the underlying bytes of the IPv6 address.
708 *
709 * @return A reference to the base type containing the bytes of the IPv6 address.
710 * @remark Retrieves the data representing the IP address in **network byte order** (big-endian).
711 */
713 return _data.bytes;
714 }
715
716 /**
717 * Determines if the IPv6 address is an IPv4-mapped address.
718 *
719 * @return An `optional` containing the mapped IPv4 address if the IPv6 address is IPv4-mapped, or an empty `optional` otherwise.
720 * @remark An IPv4-mapped IPv6 address has its first 80 bits set to zero and the next 16 bits set to one (starting with `::FFFF/96`).
721 */
723 const auto& b = bytes();
724 if (b[10] != 0xFF || b[11] != 0xFF) {
725 return nullptr;
726 }
727 ipv4_address::base_type ipv4_bytes = { b[12], b[13], b[14], b[15] };
728 return ipv4_address(ipv4_bytes);
729 }
730
731 /**
732 * Determines if the IPv6 address is a 6to4 address.
733 *
734 * @return An optional containing the encapsulated IPv4 address if the IPv6 address is a 6to4 address, or an empty optional otherwise.
735 * @remark A 6to4 address uses a `2002::/16` prefix and embeds an IPv4 address in the next 32 bits.
736 * @see [RFC 3056](https://datatracker.ietf.org/doc/html/rfc3056.html).
737 */
739 const auto& b = bytes();
740 if (b[0] != 0x20 || b[1] != 0x02) {
741 return nullptr;
742 }
743 ipv4_address::base_type ipv4_bytes = { b[2], b[3], b[4], b[5] };
744 return ipv4_address(ipv4_bytes);
745 }
746
747 /**
748 * Determines if the IPv6 address is a Teredo address.
749 *
750 * @return An optional containing a pair of IPv4 addresses representing the Teredo server and client if the IPv6 address is a Teredo address, or an empty optional otherwise.
751 * @retval std::pair::first The Teredo server IPv4 address
752 * @retval std::pair::second The Teredo client IPv4 address
753 * @remark A Teredo address begins with the `2001::/32` prefix and is used for NAT traversal for IPv6.
754 * @see [RFC 4380](https://datatracker.ietf.org/doc/html/rfc4380.html).
755 */
756 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE optional<std::pair<ipv4_address, ipv4_address>> teredo() const IPADDRESS_NOEXCEPT {
757 const auto& b = bytes();
758 if (b[0] != 0x20 || b[1] != 0x01 || b[2] != 0x00 || b[3] != 0x00) {
759 return nullptr;
760 }
761 ipv4_address::base_type server_bytes = { b[4], b[5], b[6], b[7] };
762 ipv4_address::base_type client_bytes = { uint8_t(~b[12]), uint8_t(~b[13]), uint8_t(~b[14]), uint8_t(~b[15]) };
763 return std::make_pair(ipv4_address(server_bytes), ipv4_address(client_bytes));
764 }
765
766 /**
767 * Checks if the IPv6 address is a site-local address.
768 *
769 * @return `true` if the address is site-local, `false` otherwise.
770 * @note Site-local addresses are equivalent to private addresses in IPv4 and are not routable on the global internet.
771 * @remark These attribute is true for the network as a whole if it is true for both the network address and the broadcast address.
772 */
774
775protected:
776 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_address_base() IPADDRESS_NOEXCEPT = default;
777
778 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit ipv6_address_base(const base_type& bytes) IPADDRESS_NOEXCEPT : _data(bytes) {
779 }
780
782 lhs._data.bytes.swap(rhs._data.bytes);
783 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
784 lhs._data.scope_id.swap(rhs._data.scope_id);
785 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
786 }
787
788 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t hash(const base_type& bytes) const IPADDRESS_NOEXCEPT {
789 return internal::calc_hash(
790 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
791 _data.scope_id.hash(),
792 #else // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
793 0,
794 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
795 size_t(bytes[0]), size_t(bytes[1]), size_t(bytes[2]), size_t(bytes[3]),
796 size_t(bytes[4]), size_t(bytes[5]), size_t(bytes[6]), size_t(bytes[7]),
797 size_t(bytes[8]), size_t(bytes[9]), size_t(bytes[10]), size_t(bytes[11]),
798 size_t(bytes[12]), size_t(bytes[13]), size_t(bytes[14]), size_t(bytes[15]));
799 }
800
802 return lhs._data.bytes == rhs._data.bytes
803
804 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
805 && lhs._data.scope_id.compare(rhs._data.scope_id) == 0
806 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
807 ;
808 }
809
811 return lhs._data.bytes < rhs._data.bytes
812
813 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
814 ? true : lhs._data.scope_id.compare(rhs._data.scope_id) < 0;
815 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
816 ;
817 }
818
819#ifdef IPADDRESS_HAS_SPACESHIP_OPERATOR
820
822 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
824 if (const auto scope = lhs._data.scope_id.compare(rhs._data.scope_id); scope < 0) {
825 return std::strong_ordering::less;
826 } else if (scope == 0) {
828 } else {
829 return std::strong_ordering::greater;
830 }
831 } else {
832 return result;
833 }
834 #else // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
835 return lhs._data.bytes <=> rhs._data.bytes;
836 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
837 }
838
839#endif // IPADDRESS_HAS_SPACESHIP_OPERATOR
840
841 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t ip_to_chars(const base_type& bytes, format fmt, char (&result)[base_max_string_len + 1]) const IPADDRESS_NOEXCEPT {
842 return base_v6<ipv6_address_base>::ip_to_chars(bytes,
843
844 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
845 _data.scope_id,
846 #else // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
847 make_fixed_string(""),
848 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH <= 0
849 fmt,
850 result);
851 }
852
853private:
855
856 template <typename>
857 friend class ip_network_base;
858
859 struct ipv6_data {
860 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_data() IPADDRESS_NOEXCEPT = default;
861 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_data(const base_type& b) IPADDRESS_NOEXCEPT : bytes(b) {
862 }
863
864 base_type bytes{};
865 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH > 0
866 fixed_string<IPADDRESS_IPV6_SCOPE_MAX_LENGTH> scope_id;
867 #endif // IPADDRESS_IPV6_SCOPE_MAX_LENGTH
868 } _data;
869}; // ipv6_address_base
870
871/**
872 * Alias for the base class specialized for IPv6 address manipulation.
873 *
874 * This alias provides a convenient shorthand for the specialized `ip_address_base` class
875 * tailored for IPv6 address handling. It inherits all functionalities from the `ipv6_address_base`
876 * class, allowing for operations such as conversion, comparison, and property querying
877 * specific to IPv6 addresses.
878 */
880
881#ifdef IPADDRESS_NONTYPE_TEMPLATE_PARAMETER
882
883 /**
884 * User-defined literal for creating an ipv6_address from a fixed string at compile time.
885 *
886 * @tparam FixedString A compile-time fixed string representing the IPv6 address.
887 * @return An ipv6_address object parsed from the fixed string.
888 */
889 IPADDRESS_EXPORT template <fixed_string FixedString>
890 IPADDRESS_NODISCARD IPADDRESS_CONSTEVAL IPADDRESS_FORCE_INLINE ipv6_address operator""_ipv6() IPADDRESS_NOEXCEPT {
891 return ipv6_address::parse<FixedString>();
892 }
893
894#else // IPADDRESS_NONTYPE_TEMPLATE_PARAMETER
895
896 /**
897 * User-defined literal for creating an ipv6_address from a string literal.
898 *
899 * @param[in] address A pointer to a character array representing the IPv6 address.
900 * @param[in] size The size of the character array.
901 * @return An ipv6_address object parsed from the string literal.
902 */
903 IPADDRESS_EXPORT IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_address operator""_ipv6(const char* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
904 return internal::parse_ip_from_literal<ipv6_address_base, char, ipv6_address::base_max_string_len>(address, size);
905 }
906
907 /**
908 * User-defined literal for creating an ipv6_address from a wide string literal.
909 *
910 * @param[in] address A pointer to a character array representing the IPv6 address.
911 * @param[in] size The size of the character array.
912 * @return An ipv6_address object parsed from the string literal.
913 */
914 IPADDRESS_EXPORT IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_address operator""_ipv6(const wchar_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
915 return internal::parse_ip_from_literal<ipv6_address_base, wchar_t, ipv6_address::base_max_string_len>(address, size);
916 }
917
918 /**
919 * User-defined literal for creating an ipv6_address from a UTF-16 string literal.
920 *
921 * @param[in] address A pointer to a character array representing the IPv6 address.
922 * @param[in] size The size of the character array.
923 * @return An ipv6_address object parsed from the string literal.
924 */
925 IPADDRESS_EXPORT IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_address operator""_ipv6(const char16_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
926 return internal::parse_ip_from_literal<ipv6_address_base, char16_t, ipv6_address::base_max_string_len>(address, size);
927 }
928
929 /**
930 * User-defined literal for creating an ipv6_address from a UTF-32 string literal.
931 *
932 * @param[in] address A pointer to a character array representing the IPv6 address.
933 * @param[in] size The size of the character array.
934 * @return An ipv6_address object parsed from the string literal.
935 */
936 IPADDRESS_EXPORT IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv6_address operator""_ipv6(const char32_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
937 return internal::parse_ip_from_literal<ipv6_address_base, char32_t, ipv6_address::base_max_string_len>(address, size);
938 }
939
940#endif // IPADDRESS_NONTYPE_TEMPLATE_PARAMETER
941
942} // namespace IPADDRESS_NAMESPACE
943
944#endif // IPADDRESS_IPV6_ADDRESS_HPP
A template class providing the base functionality for IPv6 addresses.
Definition base-v6.hpp:42
A template base class for IP address representations.
Definition ip-address-base.hpp:56
Template base class for representing a network of IP addresses.
Definition ip-network-base.hpp:32
Represents the base class for IPv6 address manipulation.
Definition ipv6-address.hpp:272
constexpr inline bool is_site_local() const noexcept
Checks if the IPv6 address is a site-local address.
Definition ip-networks.hpp:397
constexpr inline uint_type to_uint() const noexcept
Converts the IPv6 address to an unsigned integer.
Definition ipv6-address.hpp:689
constexpr inline void set_scope_id(const T(&scope_id)[N], error_code &code) noexcept
Sets the scope identifier of the IPv6 address and reports any errors encountered.
Definition ipv6-address.hpp:336
constexpr inline scope get_scope_id() const noexcept
Retrieves the scope identifier of the IPv6 address.
Definition ipv6-address.hpp:286
constexpr inline const base_type & bytes() const noexcept
Provides access to the underlying bytes of the IPv6 address.
Definition ipv6-address.hpp:712
constexpr inline void set_scope_id(const T(&scope_id)[N])
Sets the scope identifier of the IPv6 address.
Definition ipv6-address.hpp:308
constexpr inline optional< std::pair< ipv4_address, ipv4_address > > teredo() const noexcept
Determines if the IPv6 address is a Teredo address.
Definition ipv6-address.hpp:756
constexpr inline optional< ipv4_address > ipv4_mapped() const noexcept
Determines if the IPv6 address is an IPv4-mapped address.
Definition ipv6-address.hpp:722
constexpr inline optional< ipv4_address > sixtofour() const noexcept
Determines if the IPv6 address is a 6to4 address.
Definition ipv6-address.hpp:738
static constexpr inline ip_address_base< ipv6_address_base > from_uint(uint_type ip) noexcept
Creates an IPv6 address from an unsigned integer using a template parameter.
Definition ipv6-address.hpp:667
A template class to manage an optional contained value.
Definition optional.hpp:35
constexpr inline bool operator!=(const scope &rhs) const noexcept
Compares two scope objects for inequality.
Definition ipv6-address.hpp:181
inline operator std::string() const
Converts the scope object to a string representation.
Definition ipv6-address.hpp:152
constexpr inline scope(const fixed_string< IPADDRESS_IPV6_SCOPE_MAX_LENGTH > &scope_id) noexcept
Constructs a scope object with a given scope identifier.
Definition ipv6-address.hpp:96
inline std::string get_string() const
Retrieves the scope identifier as a string.
Definition ipv6-address.hpp:107
constexpr inline bool operator>(const scope &rhs) const noexcept
Checks if one scope object is greater than another.
Definition ipv6-address.hpp:215
constexpr inline operator uint32_t() const noexcept
Converts the scope object to a numeric representation.
Definition ipv6-address.hpp:161
constexpr inline bool has_uint32() const noexcept
Checks if the scope identifier has a numeric representation.
Definition ipv6-address.hpp:134
constexpr inline bool operator>=(const scope &rhs) const noexcept
Checks if one scope object is greater than or equal to another.
Definition ipv6-address.hpp:235
constexpr inline bool operator<=(const scope &rhs) const noexcept
Checks if one scope object is less than or equal to another.
Definition ipv6-address.hpp:225
constexpr inline bool has_string() const noexcept
Checks if the scope identifier has a string representation.
Definition ipv6-address.hpp:125
constexpr inline uint32_t get_uint32() const noexcept
Retrieves the scope identifier as a numeric value.
Definition ipv6-address.hpp:116
constexpr inline bool operator==(const scope &rhs) const noexcept
Compares two scope objects for equality.
Definition ipv6-address.hpp:171
constexpr inline bool operator<(const scope &rhs) const noexcept
Checks if one scope object is less than another.
Definition ipv6-address.hpp:205
constexpr inline operator bool() const noexcept
Converts the scope object to a boolean value based on the presence of a scope representation.
Definition ipv6-address.hpp:143
#define IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS
Definition config.hpp:93
#define IPADDRESS_EXPORT
Definition config.hpp:42
#define IPADDRESS_NODISCARD
Definition config.hpp:98
#define IPADDRESS_FORCE_INLINE
Definition config.hpp:112
#define IPADDRESS_NAMESPACE
Definition config.hpp:38
#define IPADDRESS_NOEXCEPT
Definition config.hpp:89
#define IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS
Definition config.hpp:102
constexpr inline bool is_little_endian() noexcept
Checks if the system is little-endian.
Definition endian.hpp:110
error_code
Enumeration of error codes for IP address parsing and validation.
Definition errors.hpp:52
@ invalid_scope_id
The scope ID in the IPv6 address is invalid.
@ no_error
Indicates the absence of any errors.
@ scope_id_is_too_long
The scope ID in the IPv6 address exceeds the maximum length.
Fixed size string class.
Definition fixed-string.hpp:29