48 static constexpr size_t base_size = 16;
49 static constexpr size_t base_max_string_len = 41 + IPADDRESS_IPV6_SCOPE_MAX_LENGTH;
50 static constexpr size_t base_max_prefixlen =
base_size * 8;
53
54
55
56
62
63
64
65
71 static constexpr size_t _min_parts = 3;
72 static constexpr size_t _max_parts = 8;
74 template <
typename Iter>
81 auto ip_and_scope = split_scope_id(begin, end, code, value);
87 const auto parts = split_parts(begin, ip_and_scope.end_ip, value, code);
93 const auto result = get_parts_bound(parts, value, code);
99 auto ip = ip_address_base<Ext>(parse_parts(parts, value, std::get<0>(result), std::get<1>(result), std::get<2>(result), code));
101 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
106 if (ip_and_scope.scope_id[0] !=
'\0') {
107 ip._data.scope_id = make_fixed_string(ip_and_scope.scope_id, code);
116 for (size_t i = 0; i < (prefixlen >> 3); ++i) {
119 auto shift = (prefixlen - ((prefixlen >> 3) << 3));
121 auto byte = 0xFF ^ uint8_t(uint8_t(0xFF) >> shift);
122 bytes[prefixlen >> 3] = byte;
124 return ip_address_base<Ext>(bytes);
128 constexpr auto hextets_count = size_t(base_size >> 1);
129 char hextets[hextets_count][5] = {};
130 const size_t max_hextets = base_size >> 1;
131 for (size_t i = 0; i < max_hextets; ++i) {
132 const uint16_t value = (uint16_t(bytes[i * 2]) << 8) | uint16_t(bytes[i * 2 + 1]);
133 to_hex(value, hextets[i]);
136 auto count = max_hextets;
137 auto has_doublecolon_start =
false;
138 auto has_doublecolon_end =
false;
141 for (size_t i = 0; i < hextets_count; ++i) {
142 auto& hextet = hextets[i];
143 for (size_t h = 0; h < 3; ++h) {
144 if (hextet[0] !=
'0') {
147 hextet[0] = hextet[1];
148 hextet[1] = hextet[2];
149 hextet[2] = hextet[3];
150 hextet[3] = hextet[4];
155 int best_doublecolon_len = 0;
156 int best_doublecolon_start = -1;
157 int doublecolon_len = 0;
158 int doublecolon_start = -1;
160 for (size_t i = 0; i < max_hextets; ++i) {
161 const auto& hextet = hextets[i];
162 if (hextet[0] ==
'0') {
163 doublecolon_len += 1;
165 if (doublecolon_start == -1) {
166 doublecolon_start =
int(i);
168 if (doublecolon_len > best_doublecolon_len) {
169 best_doublecolon_len = doublecolon_len;
170 best_doublecolon_start = doublecolon_start;
174 doublecolon_start = -1;
178 if (best_doublecolon_len > 1) {
179 const int best_doublecolon_end = best_doublecolon_start + best_doublecolon_len;
180 if (best_doublecolon_end == max_hextets) {
181 has_doublecolon_end =
true;
183 hextets[best_doublecolon_start][0] =
'\0';
184 for (
int h = best_doublecolon_start; h < max_hextets - 1; ++h) {
185 const auto lindex = h + 1;
186 const auto rindex = h + best_doublecolon_len;
187 if (rindex >= max_hextets) {
190 hextets[lindex][0] = hextets[rindex][0];
191 hextets[lindex][1] = hextets[rindex][1];
192 hextets[lindex][2] = hextets[rindex][2];
193 hextets[lindex][3] = hextets[rindex][3];
195 count -= best_doublecolon_len - 1;
197 if (best_doublecolon_start == 0) {
198 has_doublecolon_start =
true;
205 if (has_doublecolon_start) {
206 result[offset++] =
':';
208 for (size_t i = 0; i < count - 1; ++i) {
209 const auto& hextet = hextets[i];
210 for (size_t c = 0; hextet[c] !=
'\0'; ++c) {
211 result[offset++] = hextet[c];
213 result[offset++] =
':';
215 const auto hextet = hextets[count - 1];
216 for (size_t c = 0; hextet[c] !=
'\0'; ++c) {
217 result[offset++] = hextet[c];
219 if (has_doublecolon_end) {
220 result[offset++] =
':';
222 if (!scope_id.empty()) {
223 result[offset++] =
'%';
224 const auto scope_id_size = scope_id.size();
225 for (size_t i = 0; i < scope_id_size; ++i) {
226 result[offset++] = scope_id[i];
229 result[offset] =
'\0';
234 char result[base_max_string_len + 1] {};
235 const auto len = ip_to_chars(bytes, {}, format::full, result);
236 auto ip = std::string(result, len);
237 ip.erase(std::remove(ip.begin(), ip.end(),
':'), ip.end());
238 auto res = std::accumulate(std::next(ip.rbegin()), ip.rend(), std::string{ip.back()}, [](std::string a,
char b) {
239 return std::move(a) +
'.' + b;
241 return res +
".ip6.arpa";
244 template <
typename Iter>
246 size_t prefixlen = 0;
248 auto has_prefixlen =
false;
250 has_prefixlen =
true;
251 const auto c = internal::next_char_or_error(it, end, code, code_value);
255 if (c >=
'0' && c <=
'9') {
256 prefixlen = prefixlen * 10 + (c -
'0');
263 if (prefixlen > base_max_prefixlen) {
268 prefixlen = has_prefixlen ? prefixlen : base_max_prefixlen;
270 auto netmask = ip_from_prefix(prefixlen);
271 return std::make_tuple(netmask, prefixlen);
275 const auto& bytes_address = address.bytes();
276 const auto& bytes_netmask = netmask.bytes();
279 for (
auto i = 0; i < base_size; ++i) {
280 bytes[i] = bytes_address[i] & bytes_netmask[i];
283 if (bytes != bytes_address) {
288 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
289 auto ip = ip_address_base<Ext>(bytes);
290 if (address._data.scope_id[0] !=
'\0') {
291 ip._data.scope_id = address._data.scope_id;
295 return ip_address_base<Ext>(bytes);
303 template <
typename Iter>
304 struct ip_and_scope {
306 char scope_id[IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1];
309 template <
typename Iter>
311 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
316 ip_and_scope<Iter> result{};
318 const auto c = internal::next_char_or_error(it, end, error, error_value);
322 if (!scope && c !=
'%') {
325 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
326 if (index > IPADDRESS_IPV6_SCOPE_MAX_LENGTH - 1) {
331 if (internal::is_invalid_scope_id_symbol(c)) {
335 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
336 result.scope_id[index++] = c;
342 #if IPADDRESS_IPV6_SCOPE_MAX_LENGTH
> 0
343 if (scope && result.scope_id[0] ==
'\0') {
351 template <
typename Iter>
353 IPADDRESS_CONSTEXPR std::array<fixed_string<4>, _max_parts + 1> empty_parts = {
354 make_fixed_string(
"\0\0\0\0"),
355 make_fixed_string(
"\0\0\0\0"),
356 make_fixed_string(
"\0\0\0\0"),
357 make_fixed_string(
"\0\0\0\0"),
358 make_fixed_string(
"\0\0\0\0"),
359 make_fixed_string(
"\0\0\0\0"),
360 make_fixed_string(
"\0\0\0\0"),
361 make_fixed_string(
"\0\0\0\0"),
362 make_fixed_string(
"\0\0\0\0")};
364 char parts[_max_parts + 1][5] = {};
365 char last_part[17] = {};
370 bool has_double_colon =
false;
373 uint32_t error_symbol = 0;
376 auto c = internal::next_char_or_error(it, end, error, error_symbol);
378 parts_count = error_symbol;
381 if (!has_double_colon && c ==
':' && prev_c ==
':') {
382 has_double_colon =
true;
384 if (parts_count > _max_parts) {
385 error = has_double_colon
395 last_part[symbol++] = c;
396 last_part[symbol] =
'\0';
403 auto& current_part = parts[parts_count++];
404 current_part[0] = last_part[0];
405 current_part[1] = last_part[1];
406 current_part[2] = last_part[2];
407 current_part[3] = last_part[3];
415 if (parts_count > _max_parts) {
416 if (parts[0][0] ==
'\0' && parts[1][0] !=
'\0') {
418 }
else if (last_part[0] ==
'\0') {
426 auto has_ipv4 =
false;
428 for (
auto i = 0; i < symbol; ++i) {
429 if (last_part[i] ==
'.') {
436 if (parts_count + 1 >= _max_parts) {
441 auto ipv4 = ipv4_address::parse(last_part, error).to_uint();
447 to_hex(uint16_t((ipv4 >> 16) & 0xFFFF), parts[parts_count++]);
448 to_hex(uint16_t(ipv4 & 0xFFFF), parts[parts_count++]);
455 auto& current_part = parts[parts_count++];
456 current_part[0] = last_part[0];
457 current_part[1] = last_part[1];
458 current_part[2] = last_part[2];
459 current_part[3] = last_part[3];
462 if (parts_count < _min_parts) {
468 make_fixed_string(parts[0]),
469 make_fixed_string(parts[1]),
470 make_fixed_string(parts[2]),
471 make_fixed_string(parts[3]),
472 make_fixed_string(parts[4]),
473 make_fixed_string(parts[5]),
474 make_fixed_string(parts[6]),
475 make_fixed_string(parts[7]),
476 make_fixed_string(parts[8])};
481 for (size_t i = 1; i < parts_count - 1; ++i) {
482 if (parts[i].empty()) {
484 error = error_code::most_one_double_colon_permitted;
492 auto parts_hi = skip;
493 auto parts_lo = parts_count - skip - 1;
495 if (parts[0].empty()) {
502 if (parts[parts_count - 1].empty()) {
509 const auto parts_skipped = _max_parts - (parts_hi + parts_lo);
511 if (parts_skipped < 1) {
516 return { parts_hi, parts_lo, parts_skipped };
518 if (parts_count != _max_parts) {
523 if (parts[0].empty()) {
528 if (parts[parts_count - 1].empty()) {
533 return { parts_count, 0, 0 };
538 base_type result = {};
541 for (size_t i = 0; i < hi; ++i) {
542 const auto part = parse_part(parts[i], error);
543 result[index++] = uint8_t(part >> 8);
544 result[index++] = uint8_t(part & 0xFF);
546 if (error != error_code::no_error) {
550 index += skipped << 1;
552 assert(parts_count > lo);
553 for (size_t i = parts_count - lo; i < parts_count; ++i) {
554 const auto part = parse_part(parts[i], error);
555 result[index++] = uint8_t(part >> 8);
556 result[index++] = uint8_t(part & 0xFF);
558 if (error != error_code::no_error) {
567 for (size_t i = 0; i < part.size(); ++i) {
568 const auto c = part[i];
569 const auto power = pow16(part.size() - i - 1);
570 if (c >=
'0' && c <=
'9') {
571 value += (c -
'0') * power;
572 }
else if(c >=
'A' && c <=
'F') {
573 value += (c - 55) * power;
574 }
else if (c >=
'a' && c <=
'f') {
575 value += (c - 87) * power;
577 error = error_code::part_has_invalid_symbol;
588 case 2:
return 16 * 16;
589 case 3:
return 16 * 16 * 16;
591 assert(!
"Unreachable code");
597 constexpr char digits[] =
"0123456789abcdef";
598 for (
auto i = 0, j = (4 - 1) * 4; i < 4; ++i, j -= 4) {
599 result[i] = digits[(value >> j) & 0x0f];
600 result[i + 1] =
'\0';